Loading src/com/android/settings/slices/CustomSliceManager.java 0 → 100644 +88 −0 Original line number Diff line number Diff line /* * Copyright (C) 2018 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.slices; import android.content.Context; import android.net.Uri; import android.util.ArrayMap; import java.util.Map; /** * Manages custom {@link androidx.slice.Slice Slices}, which are all Slices not backed by * preferences. * <p> * By default, all Slices in Settings should be built by a * </p> */ public class CustomSliceManager { protected final Map<Uri, Class<? extends CustomSliceable>> mUriMap; private final Context mContext; public CustomSliceManager(Context context) { mContext = context; mUriMap = new ArrayMap<>(); addSlices(); } /** * Return a {@link CustomSliceable} associated to the Uri. * <p> * Do not change this method signature to accommodate for a special-case slicable - a context is * the only thing that should be needed to create the object. */ public CustomSliceable getSliceableFromUri(Uri uri) { final Class clazz = mUriMap.get(uri); if (clazz == null) { throw new IllegalArgumentException("No Slice found for uri: " + uri); } return CustomSliceable.createInstance(mContext, clazz); } /** * Return a {@link CustomSliceable} associated to the Action. * <p> * Do not change this method signature to accommodate for a special-case sliceable - a context * is the only thing that should be needed to create the object. */ public CustomSliceable getSliceableFromIntentAction(String action) { return getSliceableFromUri(Uri.parse(action)); } /** * Returns {@code true} if {@param uri} is a valid Slice Uri handled by * {@link CustomSliceManager}. */ public boolean isValidUri(Uri uri) { return mUriMap.containsKey(uri); } /** * Returns {@code true} if {@param action} is a valid intent action handled by * {@link CustomSliceManager}. */ public boolean isValidAction(String action) { return isValidUri(Uri.parse(action)); } private void addSlices() { } } No newline at end of file src/com/android/settings/slices/CustomSliceable.java 0 → 100644 +102 −0 Original line number Diff line number Diff line /* * Copyright (C) 2018 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.slices; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.net.Uri; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import androidx.slice.Slice; /** * Common functions for custom Slices. * <p> * A template for all Settings slices which are not represented by a Preference. By * standardizing the methods used by the Slice helpers, we can use generically take actions * rather than maintaining a list of all of the custom slices every time we reference Slices in * Settings. * <p> * By default, all Slices in Settings should be built through Preference Controllers extending * {@link com.android.settings.core.BasePreferenceController}, which are automatically piped * into Settings-Slices infrastructure. Cases where you should implement this interface are: * <ul> * <li>Multi-line slices</li> * <li>Slices that don't exist in the UI</li> * <li>Preferences that use a supported component, like a Switch Bar</li> * </ul> * <p> * Note that if your UI is supported because the Preference is not backed by a * {@link com.android.settings.dashboard.DashboardFragment}, then you should first convert the * existing fragment into a dashboard fragment, and then extend * {@link com.android.settings.core.BasePreferenceController}. * <p> * If you implement this interface, you should add your Slice to {@link CustomSliceManager}. */ public interface CustomSliceable { /** * @return an complete instance of the {@link Slice}. */ Slice getSlice(Context context); /** * @return a {@link android.content.ContentResolver#SCHEME_CONTENT content} {@link Uri} which * backs the {@link Slice} returned by {@link #getSlice(Context)}. */ Uri getUri(); /** * Handles the actions sent by the {@link Intent intents} bound to the {@link Slice} returned by * {@link #getSlice(Context)}. * * @param intent which has the action taken on a {@link Slice}. */ void onNotifyChange(Intent intent); /** * Settings Slices which can represent components that are updatable by the framework should * listen to changes matched to the {@link IntentFilter} returned here. * * @return an {@link IntentFilter} for updates related to the {@link Slice} returned by * {@link #getSlice(Context)}. */ default IntentFilter getIntentFilter() { return null; } /** * Build an instance of a {@link CustomSliceable} which has a {@link Context}-only constructor. */ static CustomSliceable createInstance(Context context, Class<CustomSliceable> sliceableClass) { try { //final Class<CustomSliceable> clazz = Class.forName(sliceableClassName); final Constructor<CustomSliceable> sliceable = sliceableClass.getConstructor(Context.class); final Object[] params = new Object[]{context}; return sliceable.newInstance(params); } catch (NoSuchMethodException | InstantiationException | IllegalArgumentException | InvocationTargetException | IllegalAccessException e) { throw new IllegalStateException( "Invalid sliceable class: " + sliceableClass, e); } } } No newline at end of file src/com/android/settings/slices/SettingsSliceProvider.java +27 −6 Original line number Diff line number Diff line Loading @@ -32,15 +32,15 @@ import android.util.KeyValueListParser; import android.util.Log; import android.util.Pair; import com.android.settings.bluetooth.BluetoothSliceBuilder; import com.android.settings.core.BasePreferenceController; import com.android.settings.flashlight.FlashlightSliceBuilder; import com.android.settings.location.LocationSliceBuilder; import com.android.settings.mobilenetwork.Enhanced4gLteSliceHelper; import com.android.settings.notification.ZenModeSliceBuilder; import com.android.settings.overlay.FeatureFactory; import com.android.settings.core.BasePreferenceController; import com.android.settings.wifi.WifiSliceBuilder; import com.android.settings.wifi.calling.WifiCallingSliceHelper; import com.android.settings.bluetooth.BluetoothSliceBuilder; import com.android.settingslib.SliceBroadcastRelay; import com.android.settingslib.utils.ThreadUtils; Loading Loading @@ -113,11 +113,15 @@ public class SettingsSliceProvider extends SliceProvider { public static final String EXTRA_SLICE_PLATFORM_DEFINED = "com.android.settings.slice.extra.platform"; @VisibleForTesting CustomSliceManager mCustomSliceManager; @VisibleForTesting SlicesDatabaseAccessor mSlicesDatabaseAccessor; @VisibleForTesting Map<Uri, SliceData> mSliceWeakDataCache; @VisibleForTesting Map<Uri, SliceData> mSliceDataCache; Loading @@ -135,6 +139,8 @@ public class SettingsSliceProvider extends SliceProvider { mSlicesDatabaseAccessor = new SlicesDatabaseAccessor(getContext()); mSliceDataCache = new ConcurrentHashMap<>(); mSliceWeakDataCache = new WeakHashMap<>(); mCustomSliceManager = FeatureFactory.getFactory( getContext()).getSlicesFeatureProvider().getCustomSliceManager(getContext()); return true; } Loading @@ -151,6 +157,15 @@ public class SettingsSliceProvider extends SliceProvider { @Override public void onSlicePinned(Uri sliceUri) { if (mCustomSliceManager.isValidUri(sliceUri)) { final CustomSliceable sliceable = mCustomSliceManager.getSliceableFromUri(sliceUri); final IntentFilter filter = sliceable.getIntentFilter(); if (filter != null) { registerIntentToUri(filter, sliceUri); } return; } if (WifiSliceBuilder.WIFI_URI.equals(sliceUri)) { registerIntentToUri(WifiSliceBuilder.INTENT_FILTER, sliceUri); mRegisteredUris.add(sliceUri); Loading Loading @@ -197,8 +212,14 @@ public class SettingsSliceProvider extends SliceProvider { return null; } // If adding a new Slice, do not directly match Slice URIs. // Use {@link SlicesDatabaseAccessor}. // Before adding a slice to {@link CustomSliceManager}, please get approval // from the Settings team. if (mCustomSliceManager.isValidUri(sliceUri)) { final CustomSliceable sliceable = mCustomSliceManager.getSliceableFromUri( sliceUri); return sliceable.getSlice(getContext()); } if (WifiCallingSliceHelper.WIFI_CALLING_URI.equals(sliceUri)) { return FeatureFactory.getFactory(getContext()) .getSlicesFeatureProvider() Loading src/com/android/settings/slices/SliceBroadcastReceiver.java +9 −0 Original line number Diff line number Diff line Loading @@ -71,6 +71,15 @@ public class SliceBroadcastReceiver extends BroadcastReceiver { final boolean isPlatformSlice = intent.getBooleanExtra(EXTRA_SLICE_PLATFORM_DEFINED, false /* default */); final CustomSliceManager mCustomSliceManager = FeatureFactory.getFactory( context).getSlicesFeatureProvider().getCustomSliceManager(context); if (mCustomSliceManager.isValidAction(action)) { final CustomSliceable sliceable = mCustomSliceManager.getSliceableFromIntentAction(action); sliceable.onNotifyChange(intent); return; } switch (action) { case ACTION_TOGGLE_CHANGED: final boolean isChecked = intent.getBooleanExtra(Slice.EXTRA_TOGGLE_STATE, false); Loading src/com/android/settings/slices/SlicesFeatureProvider.java +2 −0 Original line number Diff line number Diff line Loading @@ -28,6 +28,8 @@ public interface SlicesFeatureProvider { */ void indexSliceData(Context context); CustomSliceManager getCustomSliceManager(Context context); /** * Gets new WifiCallingSliceHelper object */ Loading Loading
src/com/android/settings/slices/CustomSliceManager.java 0 → 100644 +88 −0 Original line number Diff line number Diff line /* * Copyright (C) 2018 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.slices; import android.content.Context; import android.net.Uri; import android.util.ArrayMap; import java.util.Map; /** * Manages custom {@link androidx.slice.Slice Slices}, which are all Slices not backed by * preferences. * <p> * By default, all Slices in Settings should be built by a * </p> */ public class CustomSliceManager { protected final Map<Uri, Class<? extends CustomSliceable>> mUriMap; private final Context mContext; public CustomSliceManager(Context context) { mContext = context; mUriMap = new ArrayMap<>(); addSlices(); } /** * Return a {@link CustomSliceable} associated to the Uri. * <p> * Do not change this method signature to accommodate for a special-case slicable - a context is * the only thing that should be needed to create the object. */ public CustomSliceable getSliceableFromUri(Uri uri) { final Class clazz = mUriMap.get(uri); if (clazz == null) { throw new IllegalArgumentException("No Slice found for uri: " + uri); } return CustomSliceable.createInstance(mContext, clazz); } /** * Return a {@link CustomSliceable} associated to the Action. * <p> * Do not change this method signature to accommodate for a special-case sliceable - a context * is the only thing that should be needed to create the object. */ public CustomSliceable getSliceableFromIntentAction(String action) { return getSliceableFromUri(Uri.parse(action)); } /** * Returns {@code true} if {@param uri} is a valid Slice Uri handled by * {@link CustomSliceManager}. */ public boolean isValidUri(Uri uri) { return mUriMap.containsKey(uri); } /** * Returns {@code true} if {@param action} is a valid intent action handled by * {@link CustomSliceManager}. */ public boolean isValidAction(String action) { return isValidUri(Uri.parse(action)); } private void addSlices() { } } No newline at end of file
src/com/android/settings/slices/CustomSliceable.java 0 → 100644 +102 −0 Original line number Diff line number Diff line /* * Copyright (C) 2018 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.slices; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.net.Uri; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import androidx.slice.Slice; /** * Common functions for custom Slices. * <p> * A template for all Settings slices which are not represented by a Preference. By * standardizing the methods used by the Slice helpers, we can use generically take actions * rather than maintaining a list of all of the custom slices every time we reference Slices in * Settings. * <p> * By default, all Slices in Settings should be built through Preference Controllers extending * {@link com.android.settings.core.BasePreferenceController}, which are automatically piped * into Settings-Slices infrastructure. Cases where you should implement this interface are: * <ul> * <li>Multi-line slices</li> * <li>Slices that don't exist in the UI</li> * <li>Preferences that use a supported component, like a Switch Bar</li> * </ul> * <p> * Note that if your UI is supported because the Preference is not backed by a * {@link com.android.settings.dashboard.DashboardFragment}, then you should first convert the * existing fragment into a dashboard fragment, and then extend * {@link com.android.settings.core.BasePreferenceController}. * <p> * If you implement this interface, you should add your Slice to {@link CustomSliceManager}. */ public interface CustomSliceable { /** * @return an complete instance of the {@link Slice}. */ Slice getSlice(Context context); /** * @return a {@link android.content.ContentResolver#SCHEME_CONTENT content} {@link Uri} which * backs the {@link Slice} returned by {@link #getSlice(Context)}. */ Uri getUri(); /** * Handles the actions sent by the {@link Intent intents} bound to the {@link Slice} returned by * {@link #getSlice(Context)}. * * @param intent which has the action taken on a {@link Slice}. */ void onNotifyChange(Intent intent); /** * Settings Slices which can represent components that are updatable by the framework should * listen to changes matched to the {@link IntentFilter} returned here. * * @return an {@link IntentFilter} for updates related to the {@link Slice} returned by * {@link #getSlice(Context)}. */ default IntentFilter getIntentFilter() { return null; } /** * Build an instance of a {@link CustomSliceable} which has a {@link Context}-only constructor. */ static CustomSliceable createInstance(Context context, Class<CustomSliceable> sliceableClass) { try { //final Class<CustomSliceable> clazz = Class.forName(sliceableClassName); final Constructor<CustomSliceable> sliceable = sliceableClass.getConstructor(Context.class); final Object[] params = new Object[]{context}; return sliceable.newInstance(params); } catch (NoSuchMethodException | InstantiationException | IllegalArgumentException | InvocationTargetException | IllegalAccessException e) { throw new IllegalStateException( "Invalid sliceable class: " + sliceableClass, e); } } } No newline at end of file
src/com/android/settings/slices/SettingsSliceProvider.java +27 −6 Original line number Diff line number Diff line Loading @@ -32,15 +32,15 @@ import android.util.KeyValueListParser; import android.util.Log; import android.util.Pair; import com.android.settings.bluetooth.BluetoothSliceBuilder; import com.android.settings.core.BasePreferenceController; import com.android.settings.flashlight.FlashlightSliceBuilder; import com.android.settings.location.LocationSliceBuilder; import com.android.settings.mobilenetwork.Enhanced4gLteSliceHelper; import com.android.settings.notification.ZenModeSliceBuilder; import com.android.settings.overlay.FeatureFactory; import com.android.settings.core.BasePreferenceController; import com.android.settings.wifi.WifiSliceBuilder; import com.android.settings.wifi.calling.WifiCallingSliceHelper; import com.android.settings.bluetooth.BluetoothSliceBuilder; import com.android.settingslib.SliceBroadcastRelay; import com.android.settingslib.utils.ThreadUtils; Loading Loading @@ -113,11 +113,15 @@ public class SettingsSliceProvider extends SliceProvider { public static final String EXTRA_SLICE_PLATFORM_DEFINED = "com.android.settings.slice.extra.platform"; @VisibleForTesting CustomSliceManager mCustomSliceManager; @VisibleForTesting SlicesDatabaseAccessor mSlicesDatabaseAccessor; @VisibleForTesting Map<Uri, SliceData> mSliceWeakDataCache; @VisibleForTesting Map<Uri, SliceData> mSliceDataCache; Loading @@ -135,6 +139,8 @@ public class SettingsSliceProvider extends SliceProvider { mSlicesDatabaseAccessor = new SlicesDatabaseAccessor(getContext()); mSliceDataCache = new ConcurrentHashMap<>(); mSliceWeakDataCache = new WeakHashMap<>(); mCustomSliceManager = FeatureFactory.getFactory( getContext()).getSlicesFeatureProvider().getCustomSliceManager(getContext()); return true; } Loading @@ -151,6 +157,15 @@ public class SettingsSliceProvider extends SliceProvider { @Override public void onSlicePinned(Uri sliceUri) { if (mCustomSliceManager.isValidUri(sliceUri)) { final CustomSliceable sliceable = mCustomSliceManager.getSliceableFromUri(sliceUri); final IntentFilter filter = sliceable.getIntentFilter(); if (filter != null) { registerIntentToUri(filter, sliceUri); } return; } if (WifiSliceBuilder.WIFI_URI.equals(sliceUri)) { registerIntentToUri(WifiSliceBuilder.INTENT_FILTER, sliceUri); mRegisteredUris.add(sliceUri); Loading Loading @@ -197,8 +212,14 @@ public class SettingsSliceProvider extends SliceProvider { return null; } // If adding a new Slice, do not directly match Slice URIs. // Use {@link SlicesDatabaseAccessor}. // Before adding a slice to {@link CustomSliceManager}, please get approval // from the Settings team. if (mCustomSliceManager.isValidUri(sliceUri)) { final CustomSliceable sliceable = mCustomSliceManager.getSliceableFromUri( sliceUri); return sliceable.getSlice(getContext()); } if (WifiCallingSliceHelper.WIFI_CALLING_URI.equals(sliceUri)) { return FeatureFactory.getFactory(getContext()) .getSlicesFeatureProvider() Loading
src/com/android/settings/slices/SliceBroadcastReceiver.java +9 −0 Original line number Diff line number Diff line Loading @@ -71,6 +71,15 @@ public class SliceBroadcastReceiver extends BroadcastReceiver { final boolean isPlatformSlice = intent.getBooleanExtra(EXTRA_SLICE_PLATFORM_DEFINED, false /* default */); final CustomSliceManager mCustomSliceManager = FeatureFactory.getFactory( context).getSlicesFeatureProvider().getCustomSliceManager(context); if (mCustomSliceManager.isValidAction(action)) { final CustomSliceable sliceable = mCustomSliceManager.getSliceableFromIntentAction(action); sliceable.onNotifyChange(intent); return; } switch (action) { case ACTION_TOGGLE_CHANGED: final boolean isChecked = intent.getBooleanExtra(Slice.EXTRA_TOGGLE_STATE, false); Loading
src/com/android/settings/slices/SlicesFeatureProvider.java +2 −0 Original line number Diff line number Diff line Loading @@ -28,6 +28,8 @@ public interface SlicesFeatureProvider { */ void indexSliceData(Context context); CustomSliceManager getCustomSliceManager(Context context); /** * Gets new WifiCallingSliceHelper object */ Loading