Loading res/xml/display_settings.xml +3 −3 Original line number Diff line number Diff line Loading @@ -25,8 +25,7 @@ <Preference android:key="brightness" android:title="@string/brightness" settings:keywords="@string/keywords_display_brightness_level" settings:controller="com.android.settings.display.AutoBrightnessPreferenceController"> settings:keywords="@string/keywords_display_brightness_level"> <intent android:action="com.android.intent.action.SHOW_BRIGHTNESS_DIALOG" /> </Preference> Loading @@ -43,7 +42,8 @@ android:key="auto_brightness" android:title="@string/auto_brightness_title" settings:keywords="@string/keywords_display_auto_brightness" android:summary="@string/auto_brightness_summary" /> android:summary="@string/auto_brightness_summary" settings:controller="com.android.settings.display.AutoBrightnessPreferenceController" /> <com.android.settingslib.RestrictedPreference android:key="wallpaper" Loading src/com/android/settings/overlay/FeatureFactory.java +3 −0 Original line number Diff line number Diff line Loading @@ -34,6 +34,7 @@ import com.android.settings.gestures.AssistGestureFeatureProvider; import com.android.settings.localepicker.LocaleFeatureProvider; import com.android.settings.security.SecurityFeatureProvider; import com.android.settings.search.SearchFeatureProvider; import com.android.settings.slices.SlicesFeatureProvider; import com.android.settings.users.UserFeatureProvider; /** Loading Loading @@ -106,6 +107,8 @@ public abstract class FeatureFactory { public abstract SmsMirroringFeatureProvider getSmsMirroringFeatureProvider(); public abstract SlicesFeatureProvider getSlicesFeatureProvider(); public static final class FactoryNotFoundException extends RuntimeException { public FactoryNotFoundException(Throwable throwable) { super("Unable to create factory. Did you misconfigure Proguard?", throwable); Loading src/com/android/settings/overlay/FeatureFactoryImpl.java +11 −0 Original line number Diff line number Diff line Loading @@ -48,6 +48,8 @@ import com.android.settings.search.SearchFeatureProvider; import com.android.settings.search.SearchFeatureProviderImpl; import com.android.settings.security.SecurityFeatureProvider; import com.android.settings.security.SecurityFeatureProviderImpl; import com.android.settings.slices.SlicesFeatureProvider; import com.android.settings.slices.SlicesFeatureProviderImpl; import com.android.settings.users.UserFeatureProvider; import com.android.settings.users.UserFeatureProviderImpl; import com.android.settings.wrapper.ConnectivityManagerWrapper; Loading Loading @@ -75,6 +77,7 @@ public class FeatureFactoryImpl extends FeatureFactory { private BluetoothFeatureProvider mBluetoothFeatureProvider; private DataPlanFeatureProvider mDataPlanFeatureProvider; private SmsMirroringFeatureProvider mSmsMirroringFeatureProvider; private SlicesFeatureProvider mSlicesFeatureProvider; @Override public SupportFeatureProvider getSupportFeatureProvider(Context context) { Loading Loading @@ -208,4 +211,12 @@ public class FeatureFactoryImpl extends FeatureFactory { } return mSmsMirroringFeatureProvider; } @Override public SlicesFeatureProvider getSlicesFeatureProvider() { if (mSlicesFeatureProvider == null) { mSlicesFeatureProvider = new SlicesFeatureProviderImpl(); } return mSlicesFeatureProvider; } } src/com/android/settings/slices/SliceData.java +1 −6 Original line number Diff line number Diff line Loading @@ -20,8 +20,7 @@ import android.net.Uri; import android.text.TextUtils; /** * TODO (b/67996923) Add SlicesIndexingManager * Data class representing a slice stored by {@link SlicesIndexingManager}. * Data class representing a slice stored by {@link SlicesIndexer}. * Note that {@link #key} is treated as a primary key for this class and determines equality. */ public class SliceData { Loading Loading @@ -173,10 +172,6 @@ public class SliceData { throw new IllegalStateException("Preference Controller cannot be empty"); } if (mUri == null) { throw new IllegalStateException("Uri cannot be null"); } return new SliceData(this); } Loading src/com/android/settings/slices/SliceDataConverter.java 0 → 100644 +202 −0 Original line number Diff line number Diff line /* * 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.slices; import android.content.Context; import android.content.res.Resources; import android.content.res.XmlResourceParser; import android.provider.SearchIndexableResource; import android.support.annotation.DrawableRes; import android.text.TextUtils; import android.util.AttributeSet; import android.util.Log; import android.util.Xml; import com.android.settings.dashboard.DashboardFragment; import com.android.settings.search.DatabaseIndexingUtils; import com.android.settings.search.Indexable.SearchIndexProvider; import com.android.settings.search.SearchIndexableResources; import com.android.settings.search.XmlParserUtils; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.List; /** * Converts {@link DashboardFragment} to {@link SliceData}. */ class SliceDataConverter { private static final String TAG = "SliceDataConverter"; private static final String NODE_NAME_PREFERENCE_SCREEN = "PreferenceScreen"; private Context mContext; private List<SliceData> mSliceData; public SliceDataConverter(Context context) { mContext = context; mSliceData = new ArrayList<>(); } /** * @return a list of {@link SliceData} to be indexed and later referenced as a Slice. * * The collection works as follows: * - Collects a list of Fragments from {@link SearchIndexableResources}. * - From each fragment, grab a {@link SearchIndexProvider}. * - For each provider, collect XML resource layout and a list of * {@link com.android.settings.core.BasePreferenceController}. */ public List<SliceData> getSliceData() { if (!mSliceData.isEmpty()) { return mSliceData; } final Collection<Class> indexableClasses = SearchIndexableResources.providerValues(); for (Class clazz : indexableClasses) { final String fragmentName = clazz.getName(); final SearchIndexProvider provider = DatabaseIndexingUtils.getSearchIndexProvider( clazz); // CodeInspection test guards against the null check. Keep check in case of bad actors. if (provider == null) { Log.e(TAG, fragmentName + " dose not implement Search Index Provider"); continue; } final List<SliceData> providerSliceData = getSliceDataFromProvider(provider, fragmentName); mSliceData.addAll(providerSliceData); } return mSliceData; } private List<SliceData> getSliceDataFromProvider(SearchIndexProvider provider, String fragmentName) { final List<SliceData> sliceData = new ArrayList<>(); final List<SearchIndexableResource> resList = provider.getXmlResourcesToIndex(mContext, true /* enabled */); if (resList == null) { return sliceData; } // TODO (b/67996923) get a list of permanent NIKs and skip the invalid keys. for (SearchIndexableResource resource : resList) { int xmlResId = resource.xmlResId; if (xmlResId == 0) { Log.e(TAG, fragmentName + " provides invalid XML (0) in search provider."); continue; } List<SliceData> xmlSliceData = getSliceDataFromXML(xmlResId, fragmentName); sliceData.addAll(xmlSliceData); } return sliceData; } private List<SliceData> getSliceDataFromXML(int xmlResId, String fragmentName) { XmlResourceParser parser = null; final List<SliceData> xmlSliceData = new ArrayList<>(); String key; String title; String summary; @DrawableRes int iconResId; String controllerClassName; try { parser = mContext.getResources().getXml(xmlResId); int type; while ((type = parser.next()) != XmlPullParser.END_DOCUMENT && type != XmlPullParser.START_TAG) { // Parse next until start tag is found } String nodeName = parser.getName(); if (!NODE_NAME_PREFERENCE_SCREEN.equals(nodeName)) { throw new RuntimeException( "XML document must start with <PreferenceScreen> tag; found" + nodeName + " at " + parser.getPositionDescription()); } final int outerDepth = parser.getDepth(); final AttributeSet attrs = Xml.asAttributeSet(parser); final String screenTitle = XmlParserUtils.getDataTitle(mContext, attrs); // TODO (b/67996923) Investigate if we need headers for Slices, since they never // correspond to an actual setting. SliceData xmlSlice; while ((type = parser.next()) != XmlPullParser.END_DOCUMENT && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { continue; } // TODO (b/67996923) Non-controller Slices should become intent-only slices. // Note that without a controller, dynamic summaries are impossible. // TODO (b/67996923) This will not work if preferences have nested intens: // <pref ....> // <intent action="blab"/> </pref> controllerClassName = XmlParserUtils.getController(mContext, attrs); if (TextUtils.isEmpty(controllerClassName)) { continue; } title = XmlParserUtils.getDataTitle(mContext, attrs); key = XmlParserUtils.getDataKey(mContext, attrs); iconResId = XmlParserUtils.getDataIcon(mContext, attrs); summary = XmlParserUtils.getDataSummary(mContext, attrs); xmlSlice = new SliceData.Builder() .setKey(key) .setTitle(title) .setSummary(summary) .setIcon(iconResId) .setScreenTitle(screenTitle) .setPreferenceControllerClassName(controllerClassName) .setFragmentName(fragmentName) .build(); xmlSliceData.add(xmlSlice); } } catch (XmlPullParserException e) { Log.w(TAG, "XML Error parsing PreferenceScreen: ", e); } catch (IOException e) { Log.w(TAG, "IO Error parsing PreferenceScreen: ", e); } catch (Resources.NotFoundException e) { Log.w(TAG, "Resoucre not found error parsing PreferenceScreen: ", e); } finally { if (parser != null) parser.close(); } return xmlSliceData; } } No newline at end of file Loading
res/xml/display_settings.xml +3 −3 Original line number Diff line number Diff line Loading @@ -25,8 +25,7 @@ <Preference android:key="brightness" android:title="@string/brightness" settings:keywords="@string/keywords_display_brightness_level" settings:controller="com.android.settings.display.AutoBrightnessPreferenceController"> settings:keywords="@string/keywords_display_brightness_level"> <intent android:action="com.android.intent.action.SHOW_BRIGHTNESS_DIALOG" /> </Preference> Loading @@ -43,7 +42,8 @@ android:key="auto_brightness" android:title="@string/auto_brightness_title" settings:keywords="@string/keywords_display_auto_brightness" android:summary="@string/auto_brightness_summary" /> android:summary="@string/auto_brightness_summary" settings:controller="com.android.settings.display.AutoBrightnessPreferenceController" /> <com.android.settingslib.RestrictedPreference android:key="wallpaper" Loading
src/com/android/settings/overlay/FeatureFactory.java +3 −0 Original line number Diff line number Diff line Loading @@ -34,6 +34,7 @@ import com.android.settings.gestures.AssistGestureFeatureProvider; import com.android.settings.localepicker.LocaleFeatureProvider; import com.android.settings.security.SecurityFeatureProvider; import com.android.settings.search.SearchFeatureProvider; import com.android.settings.slices.SlicesFeatureProvider; import com.android.settings.users.UserFeatureProvider; /** Loading Loading @@ -106,6 +107,8 @@ public abstract class FeatureFactory { public abstract SmsMirroringFeatureProvider getSmsMirroringFeatureProvider(); public abstract SlicesFeatureProvider getSlicesFeatureProvider(); public static final class FactoryNotFoundException extends RuntimeException { public FactoryNotFoundException(Throwable throwable) { super("Unable to create factory. Did you misconfigure Proguard?", throwable); Loading
src/com/android/settings/overlay/FeatureFactoryImpl.java +11 −0 Original line number Diff line number Diff line Loading @@ -48,6 +48,8 @@ import com.android.settings.search.SearchFeatureProvider; import com.android.settings.search.SearchFeatureProviderImpl; import com.android.settings.security.SecurityFeatureProvider; import com.android.settings.security.SecurityFeatureProviderImpl; import com.android.settings.slices.SlicesFeatureProvider; import com.android.settings.slices.SlicesFeatureProviderImpl; import com.android.settings.users.UserFeatureProvider; import com.android.settings.users.UserFeatureProviderImpl; import com.android.settings.wrapper.ConnectivityManagerWrapper; Loading Loading @@ -75,6 +77,7 @@ public class FeatureFactoryImpl extends FeatureFactory { private BluetoothFeatureProvider mBluetoothFeatureProvider; private DataPlanFeatureProvider mDataPlanFeatureProvider; private SmsMirroringFeatureProvider mSmsMirroringFeatureProvider; private SlicesFeatureProvider mSlicesFeatureProvider; @Override public SupportFeatureProvider getSupportFeatureProvider(Context context) { Loading Loading @@ -208,4 +211,12 @@ public class FeatureFactoryImpl extends FeatureFactory { } return mSmsMirroringFeatureProvider; } @Override public SlicesFeatureProvider getSlicesFeatureProvider() { if (mSlicesFeatureProvider == null) { mSlicesFeatureProvider = new SlicesFeatureProviderImpl(); } return mSlicesFeatureProvider; } }
src/com/android/settings/slices/SliceData.java +1 −6 Original line number Diff line number Diff line Loading @@ -20,8 +20,7 @@ import android.net.Uri; import android.text.TextUtils; /** * TODO (b/67996923) Add SlicesIndexingManager * Data class representing a slice stored by {@link SlicesIndexingManager}. * Data class representing a slice stored by {@link SlicesIndexer}. * Note that {@link #key} is treated as a primary key for this class and determines equality. */ public class SliceData { Loading Loading @@ -173,10 +172,6 @@ public class SliceData { throw new IllegalStateException("Preference Controller cannot be empty"); } if (mUri == null) { throw new IllegalStateException("Uri cannot be null"); } return new SliceData(this); } Loading
src/com/android/settings/slices/SliceDataConverter.java 0 → 100644 +202 −0 Original line number Diff line number Diff line /* * 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.slices; import android.content.Context; import android.content.res.Resources; import android.content.res.XmlResourceParser; import android.provider.SearchIndexableResource; import android.support.annotation.DrawableRes; import android.text.TextUtils; import android.util.AttributeSet; import android.util.Log; import android.util.Xml; import com.android.settings.dashboard.DashboardFragment; import com.android.settings.search.DatabaseIndexingUtils; import com.android.settings.search.Indexable.SearchIndexProvider; import com.android.settings.search.SearchIndexableResources; import com.android.settings.search.XmlParserUtils; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.List; /** * Converts {@link DashboardFragment} to {@link SliceData}. */ class SliceDataConverter { private static final String TAG = "SliceDataConverter"; private static final String NODE_NAME_PREFERENCE_SCREEN = "PreferenceScreen"; private Context mContext; private List<SliceData> mSliceData; public SliceDataConverter(Context context) { mContext = context; mSliceData = new ArrayList<>(); } /** * @return a list of {@link SliceData} to be indexed and later referenced as a Slice. * * The collection works as follows: * - Collects a list of Fragments from {@link SearchIndexableResources}. * - From each fragment, grab a {@link SearchIndexProvider}. * - For each provider, collect XML resource layout and a list of * {@link com.android.settings.core.BasePreferenceController}. */ public List<SliceData> getSliceData() { if (!mSliceData.isEmpty()) { return mSliceData; } final Collection<Class> indexableClasses = SearchIndexableResources.providerValues(); for (Class clazz : indexableClasses) { final String fragmentName = clazz.getName(); final SearchIndexProvider provider = DatabaseIndexingUtils.getSearchIndexProvider( clazz); // CodeInspection test guards against the null check. Keep check in case of bad actors. if (provider == null) { Log.e(TAG, fragmentName + " dose not implement Search Index Provider"); continue; } final List<SliceData> providerSliceData = getSliceDataFromProvider(provider, fragmentName); mSliceData.addAll(providerSliceData); } return mSliceData; } private List<SliceData> getSliceDataFromProvider(SearchIndexProvider provider, String fragmentName) { final List<SliceData> sliceData = new ArrayList<>(); final List<SearchIndexableResource> resList = provider.getXmlResourcesToIndex(mContext, true /* enabled */); if (resList == null) { return sliceData; } // TODO (b/67996923) get a list of permanent NIKs and skip the invalid keys. for (SearchIndexableResource resource : resList) { int xmlResId = resource.xmlResId; if (xmlResId == 0) { Log.e(TAG, fragmentName + " provides invalid XML (0) in search provider."); continue; } List<SliceData> xmlSliceData = getSliceDataFromXML(xmlResId, fragmentName); sliceData.addAll(xmlSliceData); } return sliceData; } private List<SliceData> getSliceDataFromXML(int xmlResId, String fragmentName) { XmlResourceParser parser = null; final List<SliceData> xmlSliceData = new ArrayList<>(); String key; String title; String summary; @DrawableRes int iconResId; String controllerClassName; try { parser = mContext.getResources().getXml(xmlResId); int type; while ((type = parser.next()) != XmlPullParser.END_DOCUMENT && type != XmlPullParser.START_TAG) { // Parse next until start tag is found } String nodeName = parser.getName(); if (!NODE_NAME_PREFERENCE_SCREEN.equals(nodeName)) { throw new RuntimeException( "XML document must start with <PreferenceScreen> tag; found" + nodeName + " at " + parser.getPositionDescription()); } final int outerDepth = parser.getDepth(); final AttributeSet attrs = Xml.asAttributeSet(parser); final String screenTitle = XmlParserUtils.getDataTitle(mContext, attrs); // TODO (b/67996923) Investigate if we need headers for Slices, since they never // correspond to an actual setting. SliceData xmlSlice; while ((type = parser.next()) != XmlPullParser.END_DOCUMENT && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { continue; } // TODO (b/67996923) Non-controller Slices should become intent-only slices. // Note that without a controller, dynamic summaries are impossible. // TODO (b/67996923) This will not work if preferences have nested intens: // <pref ....> // <intent action="blab"/> </pref> controllerClassName = XmlParserUtils.getController(mContext, attrs); if (TextUtils.isEmpty(controllerClassName)) { continue; } title = XmlParserUtils.getDataTitle(mContext, attrs); key = XmlParserUtils.getDataKey(mContext, attrs); iconResId = XmlParserUtils.getDataIcon(mContext, attrs); summary = XmlParserUtils.getDataSummary(mContext, attrs); xmlSlice = new SliceData.Builder() .setKey(key) .setTitle(title) .setSummary(summary) .setIcon(iconResId) .setScreenTitle(screenTitle) .setPreferenceControllerClassName(controllerClassName) .setFragmentName(fragmentName) .build(); xmlSliceData.add(xmlSlice); } } catch (XmlPullParserException e) { Log.w(TAG, "XML Error parsing PreferenceScreen: ", e); } catch (IOException e) { Log.w(TAG, "IO Error parsing PreferenceScreen: ", e); } catch (Resources.NotFoundException e) { Log.w(TAG, "Resoucre not found error parsing PreferenceScreen: ", e); } finally { if (parser != null) parser.close(); } return xmlSliceData; } } No newline at end of file