1 /*
2  * Copyright (C) 2015 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.tv.settings.accessories;
18 
19 import static androidx.lifecycle.Lifecycle.Event.ON_PAUSE;
20 import static androidx.lifecycle.Lifecycle.Event.ON_RESUME;
21 
22 import android.annotation.CallSuper;
23 import android.bluetooth.BluetoothDevice;
24 import android.content.Context;
25 import android.graphics.Bitmap;
26 import android.graphics.Canvas;
27 import android.graphics.drawable.BitmapDrawable;
28 import android.graphics.drawable.Drawable;
29 import android.os.Bundle;
30 import android.util.SparseArray;
31 
32 import androidx.annotation.NonNull;
33 import androidx.leanback.preference.BaseLeanbackPreferenceFragment;
34 import androidx.leanback.widget.VerticalGridView;
35 import androidx.lifecycle.LifecycleOwner;
36 import androidx.preference.Preference;
37 import androidx.preference.PreferenceScreen;
38 
39 import com.android.internal.logging.nano.MetricsProto;
40 import com.android.settingslib.core.instrumentation.Instrumentable;
41 import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
42 import com.android.settingslib.core.instrumentation.VisibilityLoggerMixin;
43 import com.android.settingslib.core.lifecycle.Lifecycle;
44 import com.android.tv.settings.R;
45 
46 import java.util.List;
47 
48 /**
49  * The screen in TV settings that shows when bluetooth searching/pairing is active.
50  */
51 public class AddAccessoryPreferenceFragment extends BaseLeanbackPreferenceFragment implements
52         LifecycleOwner, Instrumentable {
53 
54     private SparseArray<Drawable> mResizedDrawables = new SparseArray<>();
55     private final Lifecycle mLifecycle = new Lifecycle(this);
56     private final VisibilityLoggerMixin mVisibilityLoggerMixin;
57 
AddAccessoryPreferenceFragment()58     public AddAccessoryPreferenceFragment() {
59         super();
60         // Mixin that logs visibility change for activity.
61         mVisibilityLoggerMixin = new VisibilityLoggerMixin(getMetricsCategory(),
62                 new MetricsFeatureProvider());
63         getLifecycle().addObserver(mVisibilityLoggerMixin);
64     }
65 
newInstance()66     public static AddAccessoryPreferenceFragment newInstance() {
67         return new AddAccessoryPreferenceFragment();
68     }
69 
70     @Override
onCreatePreferences(Bundle savedInstanceState, String rootKey)71     public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
72         final AddAccessoryActivity activity = (AddAccessoryActivity) getActivity();
73         updateList(activity.getBluetoothDevices(), activity.getCurrentTargetAddress(),
74                 activity.getCurrentTargetStatus(), activity.getCancelledAddress());
75     }
76 
updateList(List<BluetoothDevice> devices, String currentTargetAddress, String currentTargetStatus, String cancelledAddress)77     public void updateList(List<BluetoothDevice> devices, String currentTargetAddress,
78             String currentTargetStatus, String cancelledAddress) {
79         final Context themedContext = getPreferenceManager().getContext();
80 
81         PreferenceScreen screen = getPreferenceScreen();
82         if (screen == null) {
83             screen = getPreferenceManager().createPreferenceScreen(themedContext);
84             setPreferenceScreen(screen);
85         } else {
86             screen.removeAll();
87         }
88 
89         if (devices == null) {
90             return;
91         }
92 
93         // Add entries for the discovered Bluetooth devices
94         for (BluetoothDevice bt : devices) {
95             final Preference preference = new Preference(themedContext);
96             if (currentTargetAddress.equalsIgnoreCase(bt.getAddress()) &&
97                     !currentTargetStatus.isEmpty()) {
98                 preference.setSummary(currentTargetStatus);
99             } else if (cancelledAddress.equalsIgnoreCase(bt.getAddress())) {
100                 preference.setSummary(R.string.accessory_state_canceled);
101             } else {
102                 preference.setSummary(bt.getAddress());
103             }
104             preference.setKey(bt.getAddress());
105             preference.setTitle(bt.getName());
106             preference.setIcon(getDeviceDrawable(bt));
107             screen.addPreference(preference);
108         }
109     }
110 
getDeviceDrawable(BluetoothDevice device)111     private Drawable getDeviceDrawable(BluetoothDevice device) {
112         final int resId = AccessoryUtils.getImageIdForDevice(device);
113         Drawable drawable = mResizedDrawables.get(resId);
114         if (drawable == null) {
115             final Drawable tempDrawable = getActivity().getDrawable(resId);
116             final int iconWidth =
117                     getResources().getDimensionPixelSize(R.dimen.lb_dialog_list_item_icon_width);
118             final int iconHeight =
119                     getResources().getDimensionPixelSize(R.dimen.lb_dialog_list_item_icon_height);
120             tempDrawable.setBounds(0, 0, iconWidth, iconHeight);
121             final Bitmap bitmap =
122                     Bitmap.createBitmap(iconWidth, iconHeight, Bitmap.Config.ARGB_8888);
123             final Canvas canvas = new Canvas(bitmap);
124             tempDrawable.draw(canvas);
125             drawable = new BitmapDrawable(getResources(), bitmap);
126             mResizedDrawables.put(resId, drawable);
127         }
128         return drawable;
129     }
130 
131     @Override
onPreferenceTreeClick(Preference preference)132     public boolean onPreferenceTreeClick(Preference preference) {
133         final AddAccessoryActivity activity = (AddAccessoryActivity) getActivity();
134         activity.onActionClicked(preference.getKey());
135         return super.onPreferenceTreeClick(preference);
136     }
137 
advanceSelection()138     public void advanceSelection() {
139         final int preferenceCount = getPreferenceScreen().getPreferenceCount();
140         if (preferenceCount > 0) {
141             final VerticalGridView vgv = (VerticalGridView) getListView();
142             final int position = (vgv.getSelectedPosition() + 1) % preferenceCount;
143             vgv.setSelectedPositionSmooth(position);
144         }
145     }
146 
147     @Override
getMetricsCategory()148     public int getMetricsCategory() {
149         return MetricsProto.MetricsEvent.BLUETOOTH_PAIRING;
150     }
151 
152     @NonNull
153     @Override
getLifecycle()154     public Lifecycle getLifecycle() {
155         return mLifecycle;
156     }
157 
158     @CallSuper
159     @Override
onResume()160     public void onResume() {
161         mLifecycle.handleLifecycleEvent(ON_RESUME);
162         super.onResume();
163     }
164 
165     @CallSuper
166     @Override
onPause()167     public void onPause() {
168         mLifecycle.handleLifecycleEvent(ON_PAUSE);
169         super.onPause();
170     }
171 }
172