• 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.bluetooth.BluetoothAdapter;
23 import android.content.ContentResolver;
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 import android.support.v4.graphics.drawable.IconCompat;
30 
31 import com.android.internal.logging.nano.MetricsProto;
32 import com.android.settings.R;
33 import com.android.settings.SubSettings;
34 import com.android.settings.connecteddevice.BluetoothDashboardFragment;
35 import com.android.settings.search.DatabaseIndexingUtils;
36 import com.android.settings.slices.SliceBroadcastReceiver;
37 import com.android.settingslib.bluetooth.LocalBluetoothAdapter;
38 import com.android.settingslib.bluetooth.LocalBluetoothManager;
39 
40 import androidx.slice.Slice;
41 import androidx.slice.builders.ListBuilder;
42 import androidx.slice.builders.SliceAction;
43 
44 public class BluetoothSliceBuilder {
45 
46     private static final String TAG = "BluetoothSliceBuilder";
47 
48     /**
49      * Backing Uri for the Bluetooth Slice.
50      */
51     public static final Uri BLUETOOTH_URI = new Uri.Builder()
52             .scheme(ContentResolver.SCHEME_CONTENT)
53             .authority(SettingsSlicesContract.AUTHORITY)
54             .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
55             .appendPath(SettingsSlicesContract.KEY_BLUETOOTH)
56             .build();
57 
58     /**
59      * Action notifying a change on the BluetoothSlice.
60      */
61     public static final String ACTION_BLUETOOTH_SLICE_CHANGED =
62             "com.android.settings.bluetooth.action.BLUETOOTH_MODE_CHANGED";
63 
64     public static final IntentFilter INTENT_FILTER = new IntentFilter();
65 
66     static {
67         INTENT_FILTER.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED);
68         INTENT_FILTER.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
69     }
70 
BluetoothSliceBuilder()71     private BluetoothSliceBuilder() {
72     }
73 
74     /**
75      * Return a Bluetooth Slice bound to {@link #BLUETOOTH_URI}.
76      * <p>
77      * Note that you should register a listener for {@link #INTENT_FILTER} to get changes for
78      * Bluetooth.
79      */
getSlice(Context context)80     public static Slice getSlice(Context context) {
81         final boolean isBluetoothEnabled = isBluetoothEnabled();
82         final CharSequence title = context.getText(R.string.bluetooth_settings);
83         final IconCompat icon = IconCompat.createWithResource(context,
84                 R.drawable.ic_settings_bluetooth);
85         @ColorInt final int color = com.android.settings.Utils.getColorAccent(context);
86         final PendingIntent toggleAction = getBroadcastIntent(context);
87         final PendingIntent primaryAction = getPrimaryAction(context);
88         final SliceAction primarySliceAction = new SliceAction(primaryAction, icon, title);
89         final SliceAction toggleSliceAction = new SliceAction(toggleAction, null /* actionTitle */,
90                 isBluetoothEnabled);
91 
92         return new ListBuilder(context, BLUETOOTH_URI, ListBuilder.INFINITY)
93                 .setAccentColor(color)
94                 .addRow(b -> b
95                         .setTitle(title)
96                         .addEndItem(toggleSliceAction)
97                         .setPrimaryAction(primarySliceAction))
98                 .build();
99     }
100 
getIntent(Context context)101     public static Intent getIntent(Context context) {
102         final String screenTitle = context.getText(R.string.bluetooth_settings_title).toString();
103         final Uri contentUri = new Uri.Builder().appendPath(
104                 SettingsSlicesContract.KEY_BLUETOOTH).build();
105         return DatabaseIndexingUtils.buildSearchResultPageIntent(context,
106                 BluetoothDashboardFragment.class.getName(), null /* key */, screenTitle,
107                 MetricsProto.MetricsEvent.SETTINGS_CONNECTED_DEVICE_CATEGORY)
108                 .setClassName(context.getPackageName(), SubSettings.class.getName())
109                 .setData(contentUri);
110     }
111 
112     /**
113      * Update the current Bluetooth status to the boolean value keyed by
114      * {@link android.app.slice.Slice#EXTRA_TOGGLE_STATE} on {@param intent}.
115      */
handleUriChange(Context context, Intent intent)116     public static void handleUriChange(Context context, Intent intent) {
117         final boolean newBluetoothState = intent.getBooleanExtra(EXTRA_TOGGLE_STATE, false);
118         final LocalBluetoothAdapter adapter = LocalBluetoothManager.getInstance(context,
119                 null /* callback */).getBluetoothAdapter();
120 
121         adapter.setBluetoothEnabled(newBluetoothState);
122         // Do not notifyChange on Uri. The service takes longer to update the current value than it
123         // does for the Slice to check the current value again. Let {@link SliceBroadcastRelay}
124         // handle it.
125     }
126 
isBluetoothEnabled()127     private static boolean isBluetoothEnabled() {
128         final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
129         return adapter.isEnabled();
130     }
131 
getPrimaryAction(Context context)132     private static PendingIntent getPrimaryAction(Context context) {
133         final Intent intent = getIntent(context);
134         return PendingIntent.getActivity(context, 0 /* requestCode */,
135                 intent, 0 /* flags */);
136     }
137 
getBroadcastIntent(Context context)138     private static PendingIntent getBroadcastIntent(Context context) {
139         final Intent intent = new Intent(ACTION_BLUETOOTH_SLICE_CHANGED)
140                 .setClass(context, SliceBroadcastReceiver.class);
141         return PendingIntent.getBroadcast(context, 0 /* requestCode */, intent,
142                 PendingIntent.FLAG_CANCEL_CURRENT);
143     }
144 }
145