• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 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.settings.bluetooth;
17 
18 import static android.app.slice.Slice.EXTRA_TOGGLE_STATE;
19 
20 import android.annotation.ColorInt;
21 import android.app.PendingIntent;
22 import android.app.settings.SettingsEnums;
23 import android.bluetooth.BluetoothAdapter;
24 import android.content.Context;
25 import android.content.Intent;
26 import android.content.IntentFilter;
27 import android.net.Uri;
28 import android.provider.SettingsSlicesContract;
29 
30 import androidx.core.graphics.drawable.IconCompat;
31 import androidx.slice.Slice;
32 import androidx.slice.builders.ListBuilder;
33 import androidx.slice.builders.ListBuilder.RowBuilder;
34 import androidx.slice.builders.SliceAction;
35 
36 import com.android.settings.R;
37 import com.android.settings.SubSettings;
38 import com.android.settings.connecteddevice.BluetoothDashboardFragment;
39 import com.android.settings.slices.CustomSliceRegistry;
40 import com.android.settings.slices.SliceBroadcastReceiver;
41 import com.android.settings.slices.SliceBuilderUtils;
42 
43 /**
44  * Utility class to build a Bluetooth Slice, and handle all associated actions.
45  */
46 public class BluetoothSliceBuilder {
47 
48     private static final String TAG = "BluetoothSliceBuilder";
49 
50     /**
51      * Action notifying a change on the BluetoothSlice.
52      */
53     public static final String ACTION_BLUETOOTH_SLICE_CHANGED =
54             "com.android.settings.bluetooth.action.BLUETOOTH_MODE_CHANGED";
55 
56     public static final IntentFilter INTENT_FILTER = new IntentFilter();
57 
58     static {
59         INTENT_FILTER.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED);
60         INTENT_FILTER.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
61     }
62 
BluetoothSliceBuilder()63     private BluetoothSliceBuilder() {
64     }
65 
66     /**
67      * Return a Bluetooth Slice bound to {@link CustomSliceRegistry#BLUETOOTH_URI}.
68      * <p>
69      * Note that you should register a listener for {@link #INTENT_FILTER} to get changes for
70      * Bluetooth.
71      */
getSlice(Context context)72     public static Slice getSlice(Context context) {
73         final boolean isBluetoothEnabled = isBluetoothEnabled();
74         final CharSequence title = context.getText(R.string.bluetooth_settings);
75         final IconCompat icon = IconCompat.createWithResource(context,
76                 com.android.internal.R.drawable.ic_settings_bluetooth);
77         @ColorInt final int color = com.android.settings.Utils.getColorAccent(
78                 context).getDefaultColor();
79         final PendingIntent toggleAction = getBroadcastIntent(context);
80         final PendingIntent primaryAction = getPrimaryAction(context);
81         final SliceAction primarySliceAction = SliceAction.createDeeplink(primaryAction, icon,
82                 ListBuilder.ICON_IMAGE, title);
83         final SliceAction toggleSliceAction = SliceAction.createToggle(toggleAction,
84                 null /* actionTitle */, isBluetoothEnabled);
85 
86         return new ListBuilder(context, CustomSliceRegistry.BLUETOOTH_URI, ListBuilder.INFINITY)
87                 .setAccentColor(color)
88                 .addRow(new RowBuilder()
89                         .setTitle(title)
90                         .addEndItem(toggleSliceAction)
91                         .setPrimaryAction(primarySliceAction))
92                 .build();
93     }
94 
getIntent(Context context)95     public static Intent getIntent(Context context) {
96         final String screenTitle = context.getText(R.string.bluetooth_settings_title).toString();
97         final Uri contentUri = new Uri.Builder().appendPath(
98                 SettingsSlicesContract.KEY_BLUETOOTH).build();
99         return SliceBuilderUtils.buildSearchResultPageIntent(context,
100                 BluetoothDashboardFragment.class.getName(), null /* key */, screenTitle,
101                 SettingsEnums.SETTINGS_CONNECTED_DEVICE_CATEGORY)
102                 .setClassName(context.getPackageName(), SubSettings.class.getName())
103                 .setData(contentUri);
104     }
105 
106     /**
107      * Update the current Bluetooth status to the boolean value keyed by
108      * {@link android.app.slice.Slice#EXTRA_TOGGLE_STATE} on {@param intent}.
109      */
handleUriChange(Context context, Intent intent)110     public static void handleUriChange(Context context, Intent intent) {
111         final boolean newBluetoothState = intent.getBooleanExtra(EXTRA_TOGGLE_STATE, false);
112         final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
113 
114         if (newBluetoothState) {
115             adapter.enable();
116         } else {
117             adapter.disable();
118         }
119         // Do not notifyChange on Uri. The service takes longer to update the current value than it
120         // does for the Slice to check the current value again. Let {@link SliceBroadcastRelay}
121         // handle it.
122     }
123 
isBluetoothEnabled()124     private static boolean isBluetoothEnabled() {
125         final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
126         return adapter.isEnabled();
127     }
128 
getPrimaryAction(Context context)129     private static PendingIntent getPrimaryAction(Context context) {
130         final Intent intent = getIntent(context);
131         return PendingIntent.getActivity(context, 0 /* requestCode */,
132                 intent, PendingIntent.FLAG_IMMUTABLE);
133     }
134 
getBroadcastIntent(Context context)135     private static PendingIntent getBroadcastIntent(Context context) {
136         final Intent intent = new Intent(ACTION_BLUETOOTH_SLICE_CHANGED)
137                 .setClass(context, SliceBroadcastReceiver.class);
138         return PendingIntent.getBroadcast(context, 0 /* requestCode */, intent,
139                 PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE);
140     }
141 }
142