Add slice provider to settings (only provides wifi for now)

- Adds a slice provider to settings that can make a wifi slice

Test: Use SliceBrowser to look at the slice
Bug: 68378569
Change-Id: I8c73ea96a99ee9b0db4a2d7fddc5dbc2b1156da8
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 2d031ed1..ae6d041 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -251,6 +251,8 @@
                 android:value="com.android.settings.wifi.WifiSettings" />
             <meta-data android:name="com.android.settings.PRIMARY_PROFILE_CONTROLLED"
                 android:value="true" />
+            <meta-data android:name="android.metadata.SLICE_URI"
+                       android:value="content://com.android.settings.slices/wifi" />
         </activity>
 
         <!-- Keep compatibility with old shortcuts. -->
@@ -3283,6 +3285,18 @@
             </intent-filter>
         </activity>
 
+        <provider android:name=".SettingsSliceProvider"
+                  android:authorities="com.android.settings.slices"
+                  android:exported="true">
+        </provider>
+
+        <receiver
+            android:name=".SliceBroadcastReceiver" >
+            <intent-filter>
+                <action android:name="com.android.settings.slice.action.WIFI_CHANGED"/>
+            </intent-filter>
+        </receiver>
+
         <!-- This is the longest AndroidManifest.xml ever. -->
     </application>
 </manifest>
diff --git a/res/layout/search_slice_item.xml b/res/layout/search_slice_item.xml
new file mode 100644
index 0000000..1607209
--- /dev/null
+++ b/res/layout/search_slice_item.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:minHeight="?android:attr/listPreferredItemHeight"
+    android:paddingTop="16dp"
+    android:paddingBottom="16dp"
+    android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+    android:background="?android:attr/selectableItemBackground"
+    android:clipToPadding="false">
+
+    <include layout="@layout/search_icon_view"/>
+
+    <android.app.slice.widget.SliceView
+        android:id="@android:id/content"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"/>
+</LinearLayout>
\ No newline at end of file
diff --git a/src/com/android/settings/SettingsSliceProvider.java b/src/com/android/settings/SettingsSliceProvider.java
new file mode 100644
index 0000000..845dacd
--- /dev/null
+++ b/src/com/android/settings/SettingsSliceProvider.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.settings;
+
+import android.app.PendingIntent;
+import android.app.slice.Slice;
+import android.app.slice.SliceProvider;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.drawable.Icon;
+import android.net.Uri;
+import android.net.wifi.WifiInfo;
+import android.net.wifi.WifiManager;
+
+public class SettingsSliceProvider extends SliceProvider {
+    public static final String SLICE_AUTHORITY = "com.android.settings.slices";
+
+    public static final String PATH_WIFI = "wifi";
+    public static final String ACTION_WIFI_CHANGED =
+            "com.android.settings.slice.action.WIFI_CHANGED";
+    // TODO -- Associate slice URI with search result instead of separate hardcoded thing
+    public static final String[] WIFI_SEARCH_TERMS = {"wi-fi", "wifi", "internet"};
+
+    public static Uri getUri(String path) {
+        return new Uri.Builder()
+                .scheme(ContentResolver.SCHEME_CONTENT)
+                .authority(SLICE_AUTHORITY)
+                .appendPath(path).build();
+    }
+
+    @Override
+    public boolean onCreate() {
+        return true;
+    }
+
+    @Override
+    public Slice onBindSlice(Uri sliceUri) {
+        String path = sliceUri.getPath();
+        switch (path) {
+            case "/" + PATH_WIFI:
+                return createWifi(sliceUri);
+
+        }
+        throw new IllegalArgumentException("Unrecognized slice uri: " + sliceUri);
+    }
+
+    private Slice createWifi(Uri uri) {
+        // Get wifi state
+        String[] toggleHints;
+        WifiManager wifiManager = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE);
+        int wifiState = wifiManager.getWifiState();
+        boolean wifiEnabled = false;
+        String state;
+        switch (wifiState) {
+            case WifiManager.WIFI_STATE_DISABLED:
+            case WifiManager.WIFI_STATE_DISABLING:
+                state = getContext().getString(R.string.disconnected);
+                break;
+            case WifiManager.WIFI_STATE_ENABLED:
+            case WifiManager.WIFI_STATE_ENABLING:
+                state = wifiManager.getConnectionInfo().getSSID();
+                WifiInfo.removeDoubleQuotes(state);
+                wifiEnabled = true;
+                break;
+            case WifiManager.WIFI_STATE_UNKNOWN:
+            default:
+                state = ""; // just don't show anything?
+                break;
+        }
+        if (wifiEnabled) {
+            toggleHints = new String[] {Slice.HINT_TOGGLE, Slice.HINT_SELECTED};
+        } else {
+            toggleHints = new String[] {Slice.HINT_TOGGLE};
+        }
+        // Construct the slice
+        Slice.Builder b = new Slice.Builder(uri);
+        b.addSubSlice(new Slice.Builder(b)
+                .addAction(getIntent("android.settings.WIFI_SETTINGS"),
+                        new Slice.Builder(b)
+                                .addText(getContext().getString(R.string.wifi_settings), null)
+                                .addText(state, null)
+                                .addIcon(Icon.createWithResource(getContext(),
+                                        R.drawable.ic_settings_wireless), null, Slice.HINT_HIDDEN)
+                                .addHints(Slice.HINT_TITLE)
+                                .build())
+                .addAction(getBroadcastIntent(ACTION_WIFI_CHANGED),
+                        new Slice.Builder(b)
+                                .addHints(toggleHints)
+                                .build())
+                .build());
+        return b.build();
+    }
+
+    private PendingIntent getIntent(String action) {
+        Intent intent = new Intent(action);
+        PendingIntent pi = PendingIntent.getActivity(getContext(), 0, intent, 0);
+        return pi;
+    }
+
+    private PendingIntent getBroadcastIntent(String action) {
+        Intent intent = new Intent(action);
+        intent.setClass(getContext(), SliceBroadcastReceiver.class);
+        return PendingIntent.getBroadcast(getContext(), 0, intent,
+                PendingIntent.FLAG_CANCEL_CURRENT);
+    }
+}
diff --git a/src/com/android/settings/SliceBroadcastReceiver.java b/src/com/android/settings/SliceBroadcastReceiver.java
new file mode 100644
index 0000000..f43e3a3
--- /dev/null
+++ b/src/com/android/settings/SliceBroadcastReceiver.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.settings;
+
+import static com.android.settings.SettingsSliceProvider.ACTION_WIFI_CHANGED;
+
+import android.app.slice.Slice;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.net.wifi.WifiManager;
+import android.os.Handler;
+
+/**
+ * Responds to actions performed on slices and notifies slices of updates in state changes.
+ */
+public class SliceBroadcastReceiver extends BroadcastReceiver {
+
+    @Override
+    public void onReceive(Context context, Intent i) {
+        String action = i.getAction();
+        switch (action) {
+            case ACTION_WIFI_CHANGED:
+                WifiManager wm = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
+                boolean newState = i.getBooleanExtra(Slice.EXTRA_TOGGLE_STATE, wm.isWifiEnabled());
+                wm.setWifiEnabled(newState);
+                // Wait a bit for wifi to update (TODO: is there a better way to do this?)
+                Handler h = new Handler();
+                h.postDelayed(() -> {
+                        Uri uri = SettingsSliceProvider.getUri(SettingsSliceProvider.PATH_WIFI);
+                        context.getContentResolver().notifyChange(uri, null);
+                }, 1000);
+                break;
+        }
+    }
+}