1 /*
2  * Copyright (C) 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.paintbooth.dialogs;
18 
19 import android.Manifest;
20 import android.app.Activity;
21 import android.app.AlertDialog;
22 import android.content.pm.PackageManager;
23 import android.os.Bundle;
24 import android.util.Pair;
25 import android.view.LayoutInflater;
26 import android.view.View;
27 import android.view.ViewGroup;
28 import android.widget.Button;
29 import android.widget.Toast;
30 
31 import androidx.annotation.NonNull;
32 import androidx.recyclerview.widget.RecyclerView;
33 
34 import com.android.car.ui.AlertDialogBuilder;
35 import com.android.car.ui.FocusArea;
36 import com.android.car.ui.baselayout.Insets;
37 import com.android.car.ui.baselayout.InsetsChangedListener;
38 import com.android.car.ui.core.CarUi;
39 import com.android.car.ui.paintbooth.R;
40 import com.android.car.ui.recyclerview.CarUiContentListItem;
41 import com.android.car.ui.recyclerview.CarUiListItemAdapter;
42 import com.android.car.ui.recyclerview.CarUiRadioButtonListItem;
43 import com.android.car.ui.recyclerview.CarUiRadioButtonListItemAdapter;
44 import com.android.car.ui.recyclerview.CarUiRecyclerView;
45 import com.android.car.ui.toolbar.NavButtonMode;
46 import com.android.car.ui.toolbar.ToolbarController;
47 
48 import java.util.ArrayList;
49 import java.util.List;
50 
51 /**
52  * Activity that shows different dialogs from the device default theme.
53  */
54 public class DialogsActivity extends Activity implements InsetsChangedListener {
55 
56     private final List<Pair<Integer, View.OnClickListener>> mButtons = new ArrayList<>();
57 
58     @Override
onCreate(Bundle savedInstanceState)59     protected void onCreate(Bundle savedInstanceState) {
60         super.onCreate(savedInstanceState);
61         setContentView(R.layout.car_ui_recycler_view_activity);
62         ToolbarController toolbar = CarUi.requireToolbar(this);
63         toolbar.setTitle(getTitle());
64         toolbar.setNavButtonMode(NavButtonMode.BACK);
65 
66         mButtons.add(Pair.create(R.string.dialog_show_dialog,
67                 v -> showDialog()));
68         mButtons.add(Pair.create(R.string.dialog_show_dialog_icon,
69                 v -> showDialogWithIcon()));
70         mButtons.add(Pair.create(R.string.dialog_show_dialog_edit,
71                 v -> showDialogWithTextBox()));
72         mButtons.add(Pair.create(R.string.dialog_show_dialog_only_positive,
73                 v -> showDialogWithOnlyPositiveButton()));
74         mButtons.add(Pair.create(R.string.dialog_show_dialog_no_button,
75                 v -> showDialogWithNoButtonProvided()));
76         mButtons.add(Pair.create(R.string.dialog_show_dialog_checkbox,
77                 v -> showDialogWithCheckbox()));
78         mButtons.add(Pair.create(R.string.dialog_show_dialog_no_title,
79                 v -> showDialogWithoutTitle()));
80         mButtons.add(Pair.create(R.string.dialog_show_toast,
81                 v -> showToast()));
82         mButtons.add(Pair.create(R.string.dialog_show_subtitle,
83                 v -> showDialogWithSubtitle()));
84         mButtons.add(Pair.create(R.string.dialog_show_subtitle_and_icon,
85                 v -> showDialogWithSubtitleAndIcon()));
86         mButtons.add(Pair.create(R.string.dialog_show_long_subtitle_and_icon,
87                 v -> showDialogWithLongSubtitleAndIcon()));
88         mButtons.add(Pair.create(R.string.dialog_show_single_choice,
89                 v -> showDialogWithSingleChoiceItems()));
90         mButtons.add(Pair.create(R.string.dialog_show_list_items_without_default_button,
91                 v -> showDialogWithListItemsWithoutDefaultButton()));
92         mButtons.add(Pair.create(R.string.dialog_show_unfocusable_list_items,
93                 v -> showDialogWithUnfocusableListItems()));
94         mButtons.add(Pair.create(R.string.dialog_show_empty_list_items,
95                 v -> showDialogWithEmptyList()));
96         mButtons.add(Pair.create(R.string.dialog_show_permission_dialog,
97                 v -> showPermissionDialog()));
98         mButtons.add(Pair.create(R.string.dialog_show_multi_permission_dialog,
99                 v -> showMultiPermissionDialog()));
100         mButtons.add(Pair.create(R.string.dialog_show_foreground_permission_dialog,
101                 v -> showForegroundPermissionDialog()));
102         mButtons.add(Pair.create(R.string.dialog_show_background_permission_dialog,
103                 v -> showBackgroundPermissionDialog()));
104 
105         CarUiRecyclerView recyclerView = requireViewById(R.id.list);
106         recyclerView.setAdapter(mAdapter);
107     }
108 
showDialog()109     private void showDialog() {
110         new AlertDialogBuilder(this)
111                 .setTitle(getString(R.string.standard_alert_dialog))
112                 .setMessage(getString(R.string.my_message))
113                 .setNeutralButton(getString(R.string.neutral), (dialogInterface, which) -> {
114                 })
115                 .setPositiveButton(getString(R.string.ok), (dialogInterface, which) -> {
116                 })
117                 .setNegativeButton(getString(R.string.cancel), (dialogInterface, which) -> {
118                 })
119                 .show();
120     }
121 
showDialogWithIcon()122     private void showDialogWithIcon() {
123         new AlertDialogBuilder(this)
124                 .setTitle(getString(R.string.alert_dialog_with_icon))
125                 .setMessage(getString(R.string.my_message))
126                 .setIcon(R.drawable.ic_tracklist)
127                 .show();
128     }
129 
showDialogWithNoButtonProvided()130     private void showDialogWithNoButtonProvided() {
131         new AlertDialogBuilder(this)
132                 .setTitle(getString(R.string.standard_alert_dialog))
133                 .show();
134     }
135 
showDialogWithCheckbox()136     private void showDialogWithCheckbox() {
137         new AlertDialogBuilder(this)
138                 .setTitle(R.string.custom_dialog_box)
139                 .setMultiChoiceItems(
140                         new CharSequence[]{"I am a checkbox"},
141                         new boolean[]{false},
142                         (dialog, which, isChecked) -> {
143                         })
144                 .setPositiveButton(getString(R.string.ok), (dialogInterface, which) -> {
145                 })
146                 .setNegativeButton(getString(R.string.cancel), (dialogInterface, which) -> {
147                 })
148                 .show();
149     }
150 
showDialogWithTextBox()151     private void showDialogWithTextBox() {
152         new AlertDialogBuilder(this)
153                 .setTitle(R.string.standard_alert_dialog)
154                 .setEditBox(getString(R.string.edit_me_please), null, null)
155                 .setAutoDescUpdateForWidescreen(true)
156                 .setEditTextTitleAndDescForWideScreen("title", "desc from app")
157                 .setPositiveButton("OK", (dialogInterface, i) -> {
158                 })
159                 .show();
160     }
161 
showDialogWithOnlyPositiveButton()162     private void showDialogWithOnlyPositiveButton() {
163         new AlertDialogBuilder(this)
164                 .setTitle(R.string.standard_alert_dialog)
165                 .setMessage(getString(R.string.my_message))
166                 .setPositiveButton(getString(R.string.ok), (dialogInterface, i) -> {
167                 })
168                 .show();
169     }
170 
showDialogWithoutTitle()171     private void showDialogWithoutTitle() {
172         new AlertDialogBuilder(this)
173                 .setMessage(R.string.no_title_message)
174                 .setPositiveButton(getString(R.string.ok), (dialogInterface, i) -> {
175                 })
176                 .setNegativeButton(getString(R.string.cancel), (dialogInterface, which) -> {
177                 })
178                 .show();
179     }
180 
showToast()181     private void showToast() {
182         Toast.makeText(this, "Toast message looks like this", Toast.LENGTH_LONG).show();
183     }
184 
showDialogWithSubtitle()185     private void showDialogWithSubtitle() {
186         new AlertDialogBuilder(this)
187                 .setTitle(R.string.my_title)
188                 .setSubtitle(R.string.my_subtitle)
189                 .setMessage(getString(R.string.my_message))
190                 .show();
191     }
192 
showDialogWithSingleChoiceItems()193     private void showDialogWithSingleChoiceItems() {
194         ArrayList<CarUiRadioButtonListItem> data = new ArrayList<>();
195 
196         CarUiRadioButtonListItem item = new CarUiRadioButtonListItem();
197         item.setTitle(getString(R.string.first_item));
198         data.add(item);
199 
200         item = new CarUiRadioButtonListItem();
201         item.setTitle(getString(R.string.second_item));
202         data.add(item);
203 
204         item = new CarUiRadioButtonListItem();
205         item.setTitle(getString(R.string.third_item));
206         data.add(item);
207 
208         new AlertDialogBuilder(this)
209                 .setTitle(R.string.select_one_option)
210                 .setSubtitle(R.string.select_one_option_at_a_time)
211                 .setSingleChoiceItems(new CarUiRadioButtonListItemAdapter(data), null)
212                 .show();
213     }
214 
showDialogWithListItemsWithoutDefaultButton()215     private void showDialogWithListItemsWithoutDefaultButton() {
216         ArrayList<CarUiContentListItem> data = new ArrayList<>();
217         AlertDialog[] dialog = new AlertDialog[1];
218 
219         CarUiContentListItem item = new CarUiContentListItem(CarUiContentListItem.Action.NONE);
220         item.setTitle("First item");
221         item.setOnItemClickedListener(i -> dialog[0].dismiss());
222         data.add(item);
223 
224 
225         item = new CarUiContentListItem(CarUiContentListItem.Action.NONE);
226         item.setTitle("Second item");
227         item.setOnItemClickedListener(i -> dialog[0].dismiss());
228         data.add(item);
229 
230         item = new CarUiContentListItem(CarUiContentListItem.Action.NONE);
231         item.setTitle("Third item");
232         item.setOnItemClickedListener(i -> dialog[0].dismiss());
233         data.add(item);
234 
235         dialog[0] = new AlertDialogBuilder(this)
236                 .setTitle("Select one option.")
237                 .setSubtitle("Ony one option may be selected at a time")
238                 .setAdapter(new CarUiListItemAdapter(data))
239                 .setAllowDismissButton(false)
240                 .show();
241     }
242 
showDialogWithUnfocusableListItems()243     private void showDialogWithUnfocusableListItems() {
244         List<CarUiContentListItem> data = new ArrayList<>();
245 
246         CarUiContentListItem item = new CarUiContentListItem(CarUiContentListItem.Action.NONE);
247         item.setTitle("First item");
248         data.add(item);
249 
250         item = new CarUiContentListItem(CarUiContentListItem.Action.NONE);
251         item.setTitle("Second item");
252         data.add(item);
253 
254         item = new CarUiContentListItem(CarUiContentListItem.Action.NONE);
255         item.setTitle("Third item");
256         data.add(item);
257 
258         item = new CarUiContentListItem(CarUiContentListItem.Action.NONE);
259         item.setTitle("Fourth item");
260         data.add(item);
261 
262         item = new CarUiContentListItem(CarUiContentListItem.Action.NONE);
263         item.setTitle("Fifth item");
264         data.add(item);
265 
266         item = new CarUiContentListItem(CarUiContentListItem.Action.NONE);
267         item.setTitle("Sixth item");
268         data.add(item);
269 
270         item = new CarUiContentListItem(CarUiContentListItem.Action.NONE);
271         item.setTitle("Seventh item");
272         data.add(item);
273 
274         new AlertDialogBuilder(this)
275                 .setTitle("Unfocusable items")
276                 .setAdapter(new CarUiListItemAdapter(data))
277                 .show();
278     }
279 
showDialogWithEmptyList()280     private void showDialogWithEmptyList() {
281         new AlertDialogBuilder(this)
282                 .setTitle("Empty list")
283                 .setAdapter(new CarUiListItemAdapter(new ArrayList<CarUiContentListItem>()))
284                 .show();
285     }
286 
showDialogWithSubtitleAndIcon()287     private void showDialogWithSubtitleAndIcon() {
288         new AlertDialogBuilder(this)
289                 .setTitle(R.string.my_title)
290                 .setSubtitle(R.string.my_subtitle)
291                 .setMessage(getString(R.string.my_message))
292                 .setIcon(R.drawable.ic_tracklist)
293                 .show();
294     }
295 
showDialogWithLongSubtitleAndIcon()296     private void showDialogWithLongSubtitleAndIcon() {
297         new AlertDialogBuilder(this)
298                 .setTitle(getString(R.string.long_title))
299                 .setSubtitle(R.string.long_subtitle)
300                 .setMessage(getString(R.string.my_message))
301                 .setIcon(R.drawable.ic_tracklist)
302                 .show();
303     }
304 
showPermissionDialog()305     private void showPermissionDialog() {
306         if (checkSelfPermission(Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) {
307             Toast.makeText(this, "Permission already granted. Remove CAMERA permission from "
308                     + "Settings > All apps > PaintBooth", Toast.LENGTH_SHORT).show();
309             return;
310         }
311         requestPermissions(new String[]{Manifest.permission.CAMERA}, 1);
312     }
313 
showMultiPermissionDialog()314     private void showMultiPermissionDialog() {
315         if (checkSelfPermission(Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED
316                 && checkSelfPermission(Manifest.permission.SEND_SMS)
317                     == PackageManager.PERMISSION_GRANTED
318                 && checkSelfPermission(Manifest.permission.READ_CONTACTS)
319                     == PackageManager.PERMISSION_GRANTED) {
320             Toast.makeText(this, "Permissions are already granted. Remove CAMERA, SEND_SMS or "
321                     + "READ_CONTACTS permission from Settings > All apps > PaintBooth",
322                     Toast.LENGTH_SHORT).show();
323             return;
324         }
325         requestPermissions(new String[]{Manifest.permission.CAMERA,
326                 Manifest.permission.READ_CONTACTS, Manifest.permission.SEND_SMS}, 1);
327     }
328 
showForegroundPermissionDialog()329     private void showForegroundPermissionDialog() {
330         requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 1);
331     }
332 
showBackgroundPermissionDialog()333     private void showBackgroundPermissionDialog() {
334         requestPermissions(new String[]{Manifest.permission.ACCESS_BACKGROUND_LOCATION}, 1);
335     }
336 
337     @Override
onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults)338     public void onRequestPermissionsResult(int requestCode, String[] permissions,
339             int[] grantResults) {
340         StringBuilder sb = new StringBuilder();
341         sb.append("Permission ");
342         for (int i = 0; i < permissions.length; i++) {
343             sb.append(permissions[i]);
344             sb.append("=");
345             sb.append(grantResults[i] == PackageManager.PERMISSION_GRANTED ? "granted" : "denied");
346             sb.append("\n");
347         }
348         Toast.makeText(this, sb.toString(), Toast.LENGTH_SHORT).show();
349     }
350 
351     private static class ViewHolder extends RecyclerView.ViewHolder {
352 
353         private final Button mButton;
354 
ViewHolder(View itemView)355         ViewHolder(View itemView) {
356             super(itemView);
357             mButton = itemView.requireViewById(R.id.button);
358         }
359 
bind(Integer title, View.OnClickListener listener)360         public void bind(Integer title, View.OnClickListener listener) {
361             mButton.setText(title);
362             mButton.setOnClickListener(listener);
363         }
364     }
365 
366     private final RecyclerView.Adapter<ViewHolder> mAdapter =
367             new RecyclerView.Adapter<ViewHolder>() {
368                 @Override
369                 public int getItemCount() {
370                     return mButtons.size();
371                 }
372 
373                 @Override
374                 public ViewHolder onCreateViewHolder(ViewGroup parent, int position) {
375                     View item =
376                             LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item,
377                                     parent, false);
378                     return new ViewHolder(item);
379                 }
380 
381                 @Override
382                 public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
383                     Pair<Integer, View.OnClickListener> pair = mButtons.get(position);
384                     holder.bind(pair.first, pair.second);
385                 }
386             };
387 
388     @Override
onCarUiInsetsChanged(@onNull Insets insets)389     public void onCarUiInsetsChanged(@NonNull Insets insets) {
390         FocusArea focusArea = requireViewById(R.id.focus_area);
391         focusArea.setBoundsOffset(0, insets.getTop(), 0, insets.getBottom());
392         focusArea.setHighlightPadding(0, insets.getTop(), 0, insets.getBottom());
393         requireViewById(R.id.list)
394                 .setPadding(0, insets.getTop(), 0, insets.getBottom());
395         requireViewById(android.R.id.content)
396                 .setPadding(insets.getLeft(), 0, insets.getRight(), 0);
397     }
398 }
399