• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.settings.common.rotary;
18 
19 import android.view.View;
20 import android.view.ViewGroup;
21 import android.view.ViewParent;
22 import android.widget.DatePicker;
23 import android.widget.NumberPicker;
24 import android.widget.TimePicker;
25 
26 import androidx.annotation.Nullable;
27 
28 import java.util.ArrayList;
29 import java.util.Arrays;
30 import java.util.HashSet;
31 import java.util.List;
32 import java.util.Set;
33 
34 /** A helper class to deal with containers holding {@link NumberPicker} instances. */
35 public final class NumberPickerUtils {
36 
37     /** Allowed containers holding {@link NumberPicker} instances. */
38     static final Set<Class> POSSIBLE_PARENT_TYPES = new HashSet<>(
39             Arrays.asList(TimePicker.class, DatePicker.class));
40 
41     /** Focuses the first child {@link NumberPicker} if it exists. */
focusChildNumberPicker(View view)42     public static boolean focusChildNumberPicker(View view) {
43         ViewGroup numberPickerParent = (ViewGroup) view;
44         List<NumberPicker> numberPickers = new ArrayList<>();
45         getNumberPickerDescendants(numberPickers, numberPickerParent);
46         if (numberPickers.isEmpty()) {
47             return false;
48         }
49         numberPickerParent.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
50         numberPickers.get(0).requestFocus();
51         return true;
52     }
53 
54     /**
55      * We don't have API access to the inner views of a {@link TimePicker} or {@link DatePicker}.
56      * We do know based on
57      * {@code frameworks/base/core/res/res/layout/time_picker_legacy_material.xml} and
58      * {@code frameworks/base/core/res/res/layout/date_picker_legacy.xml} that a {@link TimePicker}
59      * or {@link DatePicker} that is in spinner mode will be using {@link NumberPicker} instances
60      * internally, and that's what we rely on here.
61      *
62      * @param numberPickers the list to add all the {@link NumberPicker} instances found to
63      * @param view the view to search for {@link NumberPicker} instances
64      */
getNumberPickerDescendants(List<NumberPicker> numberPickers, ViewGroup view)65     public static void getNumberPickerDescendants(List<NumberPicker> numberPickers,
66             ViewGroup view) {
67         for (int i = 0; i < view.getChildCount(); i++) {
68             View child = view.getChildAt(i);
69             if (child instanceof NumberPicker) {
70                 numberPickers.add((NumberPicker) child);
71             } else if (child instanceof ViewGroup) {
72                 getNumberPickerDescendants(numberPickers, (ViewGroup) child);
73             }
74         }
75     }
76 
77     /**
78      * Determines whether {@code view1} and {@code view2} have a common ancestor of one of the types
79      * defined in {@code POSSIBLE_PARENT_TYPES}.
80      */
hasCommonNumberPickerParent(@ullable View view1, @Nullable View view2)81     static boolean hasCommonNumberPickerParent(@Nullable View view1, @Nullable View view2) {
82         if (view1 == null || view2 == null) {
83             return false;
84         }
85         View view1Ancestor = getNumberPickerParent(view1);
86         View view2Ancestor = getNumberPickerParent(view2);
87         if (view1Ancestor == null || view2Ancestor == null) {
88             return false;
89         }
90 
91         return view1Ancestor == view2Ancestor;
92     }
93 
94     /**
95      * Finds the first parent that is of one of the types defined in {@code POSSIBLE_PARENT_TYPES}.
96      * Returns {@code null} if no such parent exists.
97      */
98     @Nullable
getNumberPickerParent(@ullable View view)99     static View getNumberPickerParent(@Nullable View view) {
100         if (view == null) {
101             return null;
102         }
103 
104         if (POSSIBLE_PARENT_TYPES.contains(view.getClass())) {
105             return view;
106         }
107 
108         ViewParent viewParent = view.getParent();
109         if (viewParent instanceof View) {
110             return getNumberPickerParent((View) viewParent);
111         }
112         return null;
113     }
114 }
115