• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 package com.android.car.ui.paintbooth.toolbar;
17 
18 import android.graphics.drawable.Drawable;
19 import android.os.Bundle;
20 import android.text.Editable;
21 import android.text.InputType;
22 import android.text.TextUtils;
23 import android.text.TextWatcher;
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.appcompat.app.AppCompatActivity;
33 import androidx.recyclerview.widget.RecyclerView;
34 
35 import com.android.car.ui.AlertDialogBuilder;
36 import com.android.car.ui.FocusArea;
37 import com.android.car.ui.baselayout.Insets;
38 import com.android.car.ui.baselayout.InsetsChangedListener;
39 import com.android.car.ui.core.CarUi;
40 import com.android.car.ui.paintbooth.R;
41 import com.android.car.ui.recyclerview.CarUiRecyclerView;
42 import com.android.car.ui.toolbar.MenuItem;
43 import com.android.car.ui.toolbar.NavButtonMode;
44 import com.android.car.ui.toolbar.SearchMode;
45 import com.android.car.ui.toolbar.TabLayout;
46 import com.android.car.ui.toolbar.Toolbar;
47 import com.android.car.ui.toolbar.Toolbar.State;
48 import com.android.car.ui.toolbar.ToolbarController;
49 
50 import java.util.ArrayList;
51 import java.util.HashMap;
52 import java.util.List;
53 import java.util.Map;
54 
55 public class ToolbarActivity extends AppCompatActivity implements InsetsChangedListener {
56 
57     private final List<MenuItem> mMenuItems = new ArrayList<>();
58     private final List<Pair<CharSequence, View.OnClickListener>> mButtons = new ArrayList<>();
59 
60     @Override
onCreate(Bundle savedInstanceState)61     protected void onCreate(Bundle savedInstanceState) {
62         super.onCreate(savedInstanceState);
63         setContentView(R.layout.car_ui_recycler_view_activity);
64 
65         ToolbarController toolbar = CarUi.requireToolbar(this);
66         toolbar.setTitle(getTitle());
67         toolbar.setNavButtonMode(NavButtonMode.BACK);
68         toolbar.setLogo(R.drawable.ic_launcher);
69         boolean[] isSearching = new boolean[] { false };
70         toolbar.registerBackListener(
71                 () -> {
72                     if (toolbar.getState() == Toolbar.State.SEARCH
73                             || toolbar.getState() == Toolbar.State.EDIT) {
74                         toolbar.setState(Toolbar.State.SUBPAGE);
75                         return true;
76                     } else if (isSearching[0]) {
77                         toolbar.setSearchMode(SearchMode.DISABLED);
78                         isSearching[0] = false;
79                         return true;
80                     }
81                     return false;
82                 });
83 
84         mMenuItems.add(MenuItem.builder(this)
85                 .setToSearch()
86                 .setOnClickListener(i -> {
87                     isSearching[0] = true;
88                     toolbar.setSearchMode(SearchMode.SEARCH);
89                 })
90                 .build());
91 
92         toolbar.setMenuItems(mMenuItems);
93 
94         mButtons.add(Pair.create("Toggle progress bar", v -> {
95             toolbar.getProgressBar().setVisible(!toolbar.getProgressBar().isVisible());
96         }));
97 
98         mButtons.add(Pair.create("Change title", v ->
99                 toolbar.setTitle(toolbar.getTitle() + " X")));
100 
101         mButtons.add(Pair.create("Add/Change subtitle", v -> {
102             CharSequence subtitle = toolbar.getSubtitle();
103             if (TextUtils.isEmpty(subtitle)) {
104                 toolbar.setSubtitle("Subtitle");
105             } else {
106                 toolbar.setSubtitle(subtitle + " X");
107             }
108         }));
109 
110         mButtons.add(Pair.create(getString(R.string.toolbar_cycle_nav_button), v -> {
111             Toolbar.NavButtonMode mode = toolbar.getNavButtonMode();
112             if (mode == Toolbar.NavButtonMode.DISABLED) {
113                 toolbar.setNavButtonMode(NavButtonMode.BACK);
114             } else if (mode == Toolbar.NavButtonMode.BACK) {
115                 toolbar.setNavButtonMode(NavButtonMode.CLOSE);
116             } else if (mode == Toolbar.NavButtonMode.CLOSE) {
117                 toolbar.setNavButtonMode(NavButtonMode.DOWN);
118             } else {
119                 toolbar.setNavButtonMode(NavButtonMode.DISABLED);
120             }
121         }));
122 
123         Mutable<Boolean> hasLogo = new Mutable<>(true);
124         mButtons.add(Pair.create(getString(R.string.toolbar_toggle_logo), v -> {
125             toolbar.setLogo(hasLogo.value ? 0 : R.drawable.ic_launcher);
126             hasLogo.value = !hasLogo.value;
127         }));
128 
129         mButtons.add(Pair.create(getString(R.string.toolbar_cycle_state), v -> {
130             if (toolbar.getState() == State.HOME) {
131                 toolbar.setState(State.SUBPAGE);
132             } else if (toolbar.getState() == State.SUBPAGE) {
133                 toolbar.setState(State.EDIT);
134             } else {
135                 toolbar.setState(State.HOME);
136             }
137         }));
138 
139         mButtons.add(Pair.create(getString(R.string.toolbar_show_tabs_in_subpage), v ->
140                 toolbar.setShowTabsInSubpage(!toolbar.getShowTabsInSubpage())));
141 
142         mButtons.add(Pair.create(getString(R.string.toolbar_toggle_search_hint), v -> {
143             if (toolbar.getSearchHint().toString().contentEquals("Foo")) {
144                 toolbar.setSearchHint("Bar");
145             } else {
146                 toolbar.setSearchHint("Foo");
147             }
148         }));
149 
150         mButtons.add(Pair.create(getString(R.string.toolbar_toggle_background),
151                 v -> toolbar.setBackgroundShown(!toolbar.getBackgroundShown())));
152 
153         mButtons.add(Pair.create(getString(R.string.toolbar_add_tab), v -> toolbar.addTab(
154                 new TabLayout.Tab(getDrawable(R.drawable.ic_launcher), "Foo"))));
155 
156         mButtons.add(Pair.create(getString(R.string.toolbar_add_tab_with_custom_text), v -> {
157             SimpleTextWatcher textWatcher = new SimpleTextWatcher();
158             new AlertDialogBuilder(this)
159                     .setEditBox(null, textWatcher, null)
160                     .setTitle("Enter the text for the title")
161                     .setPositiveButton(getString(R.string.ok), (dialog, which) ->
162                             toolbar.addTab(new TabLayout.Tab(
163                                     getDrawable(R.drawable.ic_launcher),
164                                     textWatcher.getText())))
165                     .show();
166         }));
167 
168         Mutable<Boolean> showingLauncherIcon = new Mutable<>(false);
169         mButtons.add(Pair.create(getString(R.string.toolbar_toggle_search_icon), v -> {
170             if (showingLauncherIcon.value) {
171                 toolbar.setSearchIcon(null);
172             } else {
173                 toolbar.setSearchIcon(R.drawable.ic_launcher);
174             }
175             showingLauncherIcon.value = !showingLauncherIcon.value;
176         }));
177 
178         mButtons.add(Pair.create(getString(R.string.toolbar_set_xml_resource), v -> {
179             mMenuItems.clear();
180             toolbar.setMenuItems(R.xml.menuitems);
181         }));
182 
183         mButtons.add(Pair.create(getString(R.string.toolbar_add_icon), v -> {
184             mMenuItems.add(MenuItem.builder(this)
185                     .setToSettings()
186                     .setOnClickListener(i -> Toast.makeText(this, "Clicked",
187                             Toast.LENGTH_SHORT).show())
188                     .build());
189             toolbar.setMenuItems(mMenuItems);
190         }));
191 
192         mButtons.add(Pair.create(getString(R.string.toolbar_add_untined_icon), v -> {
193             mMenuItems.add(MenuItem.builder(this)
194                     .setIcon(R.drawable.ic_tracklist)
195                     .setTinted(false)
196                     .setOnClickListener(
197                             i -> Toast.makeText(this, "Clicked",
198                                     Toast.LENGTH_SHORT).show())
199                     .build());
200             toolbar.setMenuItems(mMenuItems);
201         }));
202 
203         mButtons.add(Pair.create(getString(R.string.toolbar_add_switch), v -> {
204             mMenuItems.add(MenuItem.builder(this)
205                     .setCheckable()
206                     .setOnClickListener(
207                             i ->
208                                     Toast.makeText(this,
209                                             "Checked? " + i.isChecked(),
210                                             Toast.LENGTH_SHORT)
211                                             .show())
212                     .build());
213             toolbar.setMenuItems(mMenuItems);
214         }));
215 
216         mButtons.add(Pair.create(getString(R.string.toolbar_add_text), v -> {
217             mMenuItems.add(MenuItem.builder(this)
218                     .setTitle("Baz")
219                     .setOnClickListener(
220                             i -> Toast.makeText(this, "Clicked",
221                                     Toast.LENGTH_SHORT).show())
222                     .build());
223             toolbar.setMenuItems(mMenuItems);
224         }));
225 
226         mButtons.add(Pair.create(getString(R.string.toolbar_add_icon_text), v -> {
227             mMenuItems.add(MenuItem.builder(this)
228                     .setIcon(R.drawable.ic_tracklist)
229                     .setTitle("Bar")
230                     .setShowIconAndTitle(true)
231                     .setOnClickListener(
232                             i -> Toast.makeText(this, "Clicked",
233                                     Toast.LENGTH_SHORT).show())
234                     .build());
235             toolbar.setMenuItems(mMenuItems);
236         }));
237 
238         mButtons.add(Pair.create(getString(R.string.toolbar_add_bordered_text), v -> {
239             mMenuItems.add(MenuItem.builder(this)
240                     .setTitle("Baz")
241                     .setPrimary(true)
242                     .setOnClickListener(
243                             i -> Toast.makeText(this, "Clicked",
244                                     Toast.LENGTH_SHORT).show())
245                     .build());
246             toolbar.setMenuItems(mMenuItems);
247         }));
248 
249         mButtons.add(Pair.create(getString(R.string.toolbar_add_bordered_icon_text), v -> {
250             mMenuItems.add(MenuItem.builder(this)
251                     .setIcon(R.drawable.ic_tracklist)
252                     .setTitle("Bar")
253                     .setPrimary(true)
254                     .setShowIconAndTitle(true)
255                     .setOnClickListener(
256                             i -> Toast.makeText(this, "Clicked",
257                                     Toast.LENGTH_SHORT).show())
258                     .build());
259             toolbar.setMenuItems(mMenuItems);
260         }));
261 
262         mButtons.add(Pair.create(getString(R.string.toolbar_add_untinted_icon_and_text), v -> {
263             mMenuItems.add(MenuItem.builder(this)
264                     .setIcon(R.drawable.ic_tracklist)
265                     .setTitle("Bar")
266                     .setShowIconAndTitle(true)
267                     .setTinted(false)
268                     .setOnClickListener(
269                             i -> Toast.makeText(this, "Clicked",
270                                     Toast.LENGTH_SHORT).show())
271                     .build());
272             toolbar.setMenuItems(mMenuItems);
273         }));
274 
275         mButtons.add(Pair.create(getString(R.string.toolbar_add_activatable), v -> {
276             mMenuItems.add(MenuItem.builder(this)
277                     .setIcon(R.drawable.ic_tracklist)
278                     .setActivatable()
279                     .setOnClickListener(
280                             i -> Toast.makeText(this, "Clicked",
281                                     Toast.LENGTH_SHORT).show())
282                     .build());
283             toolbar.setMenuItems(mMenuItems);
284         }));
285 
286         mButtons.add(Pair.create(getString(R.string.toolbar_add_morphing), v -> {
287             mMenuItems.add(MenuItem.builder(this)
288                     .setTitle("Become icon")
289                     .setOnClickListener(i ->
290                             i.setIcon(i.getIcon() == null ? R.drawable.ic_tracklist : 0))
291                     .build());
292             toolbar.setMenuItems(mMenuItems);
293         }));
294 
295         Mutable<Integer> overflowCounter = new Mutable<>(1);
296         mButtons.add(Pair.create(getString(R.string.toolbar_add_overflow), v -> {
297             mMenuItems.add(MenuItem.builder(this)
298                     .setTitle("Foo " + overflowCounter.value)
299                     .setOnClickListener(
300                             i -> Toast.makeText(this, "Clicked",
301                                     Toast.LENGTH_SHORT).show())
302                     .setDisplayBehavior(MenuItem.DisplayBehavior.NEVER)
303                     .build());
304             toolbar.setMenuItems(mMenuItems);
305             overflowCounter.value++;
306         }));
307 
308         mButtons.add(Pair.create(getString(R.string.toolbar_add_overflow_switch), v -> {
309             mMenuItems.add(MenuItem.builder(this)
310                     .setTitle("Foo " + overflowCounter.value)
311                     .setOnClickListener(
312                             i -> Toast.makeText(this,
313                                     i.isChecked() ? "Checked" : "Unchecked",
314                                     Toast.LENGTH_SHORT)
315                                     .show())
316                     .setDisplayBehavior(MenuItem.DisplayBehavior.NEVER)
317                     .setCheckable()
318                     .build());
319             toolbar.setMenuItems(mMenuItems);
320             overflowCounter.value++;
321         }));
322 
323         mButtons.add(Pair.create(getString(R.string.toolbar_add_icon_text_overflow), v -> {
324             mMenuItems.add(MenuItem.builder(this)
325                     .setIcon(R.drawable.ic_tracklist)
326                     .setTitle("Bar")
327                     .setShowIconAndTitle(true)
328                     .setOnClickListener(
329                             i -> Toast.makeText(this, "Clicked",
330                                     Toast.LENGTH_SHORT).show())
331                     .setDisplayBehavior(MenuItem.DisplayBehavior.NEVER)
332                     .build());
333             toolbar.setMenuItems(mMenuItems);
334         }));
335 
336         mButtons.add(Pair.create(getString(R.string.toolbar_toggle_visibility),
337                 v -> getMenuItem(item -> item.setVisible(!item.isVisible()))));
338 
339         mButtons.add(Pair.create(getString(R.string.toolbar_toggle_enable),
340                 v -> getMenuItem(item -> item.setEnabled(!item.isEnabled()))));
341 
342         mButtons.add(Pair.create(getString(R.string.toolbar_toggle_perform_click),
343                 v -> getMenuItem(MenuItem::performClick)));
344 
345         final Drawable altIcon = getDrawable(R.drawable.ic_cut);
346         Map<MenuItem, Drawable> iconBackups = new HashMap<>();
347         mButtons.add(Pair.create(getString(R.string.toolbar_toggle_icon), v ->
348                 getMenuItem(item -> {
349                     Drawable currentIcon = item.getIcon();
350                     Drawable newIcon = altIcon;
351                     if (iconBackups.containsKey(item)) {
352                         newIcon = iconBackups.get(item);
353                     }
354                     item.setIcon(newIcon);
355                     iconBackups.put(item, currentIcon);
356                 })));
357 
358         mButtons.add(Pair.create(getString(R.string.toolbar_toggle_show_while_search), v ->
359                 toolbar.setShowMenuItemsWhileSearching(
360                         !toolbar.getShowMenuItemsWhileSearching())));
361 
362         CarUiRecyclerView prv = requireViewById(R.id.list);
363         prv.setAdapter(mAdapter);
364     }
365 
366     @Override
onCarUiInsetsChanged(@onNull Insets insets)367     public void onCarUiInsetsChanged(@NonNull Insets insets) {
368         FocusArea focusArea = requireViewById(R.id.focus_area);
369         focusArea.setBoundsOffset(0, insets.getTop(), 0, insets.getBottom());
370         focusArea.setHighlightPadding(0, insets.getTop(), 0, insets.getBottom());
371         requireViewById(R.id.list)
372                 .setPadding(0, insets.getTop(), 0, insets.getBottom());
373         requireViewById(android.R.id.content)
374                 .setPadding(insets.getLeft(), 0, insets.getRight(), 0);
375     }
376 
xmlMenuItemClicked(MenuItem item)377     public void xmlMenuItemClicked(MenuItem item) {
378         Toast.makeText(this, "Xml item clicked! " + item.getTitle() + ", id: " + item.getId(),
379                 Toast.LENGTH_SHORT).show();
380     }
381 
getMenuItem(MenuItem.OnClickListener listener)382     private void getMenuItem(MenuItem.OnClickListener listener) {
383         if (mMenuItems.size() == 1) {
384             listener.onClick(mMenuItems.get(0));
385             return;
386         }
387 
388         SimpleTextWatcher textWatcher = new SimpleTextWatcher();
389         new AlertDialogBuilder(this)
390                 .setEditBox("", textWatcher, null, InputType.TYPE_CLASS_NUMBER)
391                 .setTitle("Enter the index of the MenuItem")
392                 .setPositiveButton(getString(R.string.ok), (dialog, which) -> {
393                     try {
394                         MenuItem item = mMenuItems.get(
395                                 Integer.parseInt(textWatcher.getText()));
396                         listener.onClick(item);
397                     } catch (NumberFormatException | IndexOutOfBoundsException e) {
398                         Toast.makeText(this, "Invalid index \"" + textWatcher.getText()
399                                         + "\", valid range is 0 to " + (mMenuItems.size() - 1),
400                                 Toast.LENGTH_LONG).show();
401                     }
402                 }).show();
403     }
404 
405     private static class ViewHolder extends RecyclerView.ViewHolder {
406 
407         private final Button mButton;
408 
ViewHolder(View itemView)409         ViewHolder(View itemView) {
410             super(itemView);
411             mButton = itemView.requireViewById(R.id.button);
412         }
413 
bind(CharSequence title, View.OnClickListener listener)414         public void bind(CharSequence title, View.OnClickListener listener) {
415             mButton.setText(title);
416             mButton.setOnClickListener(listener);
417         }
418     }
419 
420     private final RecyclerView.Adapter<ViewHolder> mAdapter =
421             new RecyclerView.Adapter<ViewHolder>() {
422                 @Override
423                 public int getItemCount() {
424                     return mButtons.size();
425                 }
426 
427                 @Override
428                 public ViewHolder onCreateViewHolder(ViewGroup parent, int position) {
429                     View item =
430                             LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item,
431                                     parent, false);
432                     return new ViewHolder(item);
433                 }
434 
435                 @Override
436                 public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
437                     Pair<CharSequence, View.OnClickListener> pair = mButtons.get(position);
438                     holder.bind(pair.first, pair.second);
439                 }
440             };
441 
442     /**
443      * For changing values from lambdas
444      */
445     private static final class Mutable<E> {
446 
447         public E value;
448 
Mutable()449         Mutable() {
450             value = null;
451         }
452 
Mutable(E value)453         Mutable(E value) {
454             this.value = value;
455         }
456     }
457 
458     /**
459      * Used for getting text from a dialog.
460      */
461     private static final class SimpleTextWatcher implements TextWatcher {
462 
463         private String mValue;
464 
465         @Override
beforeTextChanged(CharSequence s, int start, int count, int after)466         public void beforeTextChanged(CharSequence s, int start, int count, int after) {
467         }
468 
469         @Override
onTextChanged(CharSequence s, int start, int before, int count)470         public void onTextChanged(CharSequence s, int start, int before, int count) {
471         }
472 
473         @Override
afterTextChanged(Editable s)474         public void afterTextChanged(Editable s) {
475             mValue = s.toString();
476         }
477 
getText()478         public String getText() {
479             return mValue;
480         }
481     }
482 }
483