Loading AndroidManifest.xml +5 −0 Original line number Diff line number Diff line Loading @@ -944,6 +944,11 @@ <activity android:name="Settings$HighPowerApplicationsActivity" android:label="@string/high_power_apps" android:taskAffinity=""> <intent-filter android:priority="1"> <action android:name="android.settings.IGNORE_BATTERY_OPTIMIZATION_SETTINGS" /> <category android:name="android.intent.category.DEFAULT" /> <data android:scheme="package" /> </intent-filter> <meta-data android:name="com.android.settings.FRAGMENT_CLASS" android:value="com.android.settings.applications.ManageApplications" /> <meta-data android:name="com.android.settings.PRIMARY_PROFILE_CONTROLLED" Loading res/layout/radio_with_summary.xml 0 → 100644 +47 −0 Original line number Diff line number Diff line <?xml version="1.0" encoding="utf-8"?> <!-- Copyright (C) 2015 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. --> <com.android.settings.CheckableLinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:minHeight="?android:attr/listPreferredItemHeightSmall"> <CheckedTextView android:id="@android:id/title" android:layout_width="match_parent" android:layout_height="wrap_content" android:textAppearance="?android:attr/textAppearanceMedium" android:textColor="?android:attr/textColorAlertDialogListItem" android:gravity="center_vertical" android:paddingStart="20dp" android:paddingEnd="?android:attr/dialogPreferredPadding" android:drawableStart="?android:attr/listChoiceIndicatorSingle" android:ellipsize="marquee" /> <TextView android:id="@+android:id/summary" android:layout_width="match_parent" android:layout_height="wrap_content" android:paddingBottom="4dp" android:paddingStart="52dp" android:textAppearance="?android:attr/textAppearanceListItemSecondary" android:textColor="?android:attr/textColorSecondary" android:maxLines="10" /> </com.android.settings.CheckableLinearLayout> src/com/android/settings/CheckableLinearLayout.java 0 → 100644 +72 −0 Original line number Diff line number Diff line /* * Copyright (C) 2015 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.content.Context; import android.util.AttributeSet; import android.util.TypedValue; import android.view.View; import android.widget.Checkable; import android.widget.LinearLayout; public class CheckableLinearLayout extends LinearLayout implements Checkable { private boolean mChecked; private float mDisabledAlpha; public CheckableLinearLayout(Context context, AttributeSet attrs) { super(context, attrs); TypedValue alpha = new TypedValue(); context.getTheme().resolveAttribute(android.R.attr.disabledAlpha, alpha, true); mDisabledAlpha = alpha.getFloat(); } @Override public void setEnabled(boolean enabled) { super.setEnabled(enabled); final int N = getChildCount(); for (int i = 0; i < N; i++) { getChildAt(i).setAlpha(enabled ? 1 : mDisabledAlpha); } } @Override public void setChecked(boolean checked) { mChecked = checked; updateChecked(); } @Override public boolean isChecked() { return mChecked; } @Override public void toggle() { setChecked(!mChecked); } private void updateChecked() { final int N = getChildCount(); for (int i = 0; i < N; i++) { View child = getChildAt(i); if (child instanceof Checkable) { ((Checkable) child).setChecked(mChecked); } } } } src/com/android/settings/applications/ManageApplications.java +11 −1 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ import android.os.Environment; import android.os.UserHandle; import android.os.UserManager; import android.preference.PreferenceFrameLayout; import android.provider.Settings; import android.util.ArraySet; import android.util.Log; import android.view.LayoutInflater; Loading Loading @@ -239,6 +240,15 @@ public class ManageApplications extends InstrumentedFragment mListType = LIST_TYPE_HIGH_POWER; // Default to showing system. mShowSystem = true; if (intent != null && Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS .equals(intent.getAction())) { mCurrentPkgName = intent.getData().getSchemeSpecificPart(); if (mCurrentPkgName != null) { mCurrentUid = mApplicationsState.getEntry(mCurrentPkgName, UserHandle.myUserId()).info.uid; startApplicationDetailsActivity(); } } } else { mListType = LIST_TYPE_MAIN; } Loading Loading @@ -440,7 +450,7 @@ public class ManageApplications extends InstrumentedFragment startAppInfoFragment(AppStorageSettings.class, R.string.storage_settings); break; case LIST_TYPE_HIGH_POWER: startAppInfoFragment(HighPowerDetail.class, R.string.high_power_apps); HighPowerDetail.show(getActivity(), mCurrentPkgName); break; // TODO: Figure out if there is a way where we can spin up the profile's settings // process ahead of time, to avoid a long load of data when user clicks on a managed app. Loading src/com/android/settings/fuelgauge/HighPowerDetail.java +88 −31 Original line number Diff line number Diff line Loading @@ -16,60 +16,85 @@ package com.android.settings.fuelgauge; import android.app.Activity; import android.app.AlertDialog; import android.app.Dialog; import android.app.DialogFragment; import android.content.Context; import android.content.DialogInterface; import android.content.DialogInterface.OnClickListener; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.os.Bundle; import android.preference.Preference; import android.preference.Preference.OnPreferenceChangeListener; import android.preference.SwitchPreference; import android.util.Pair; import android.util.SparseBooleanArray; import android.view.View; import android.view.ViewGroup; import android.widget.ArrayAdapter; import android.widget.TextView; import com.android.internal.logging.MetricsLogger; import com.android.settings.R; import com.android.settings.applications.AppInfoWithHeader; import com.android.settings.applications.AppInfoBase; import com.android.settingslib.applications.ApplicationsState.AppEntry; public class HighPowerDetail extends AppInfoWithHeader implements OnPreferenceChangeListener { private static final String KEY_HIGH_POWER_SWITCH = "high_power_switch"; public class HighPowerDetail extends DialogFragment implements OnClickListener { private final PowerWhitelistBackend mBackend = PowerWhitelistBackend.getInstance(); private SwitchPreference mUsageSwitch; private String mPackageName; private CharSequence mLabel; private Adapter mAdapter; private int mSelectedIndex; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); addPreferencesFromResource(R.xml.high_power_details); mUsageSwitch = (SwitchPreference) findPreference(KEY_HIGH_POWER_SWITCH); mUsageSwitch.setOnPreferenceChangeListener(this); mPackageName = getArguments().getString(AppInfoBase.ARG_PACKAGE_NAME); PackageManager pm = getContext().getPackageManager(); try { mLabel = pm.getApplicationInfo(mPackageName, 0).loadLabel(pm); } catch (NameNotFoundException e) { mLabel = mPackageName; } mAdapter = new Adapter(getContext(), R.layout.radio_with_summary); mAdapter.add(new Pair<String, String>(getString(R.string.ignore_optimizations_on), getString(R.string.ignore_optimizations_on_desc))); mAdapter.add(new Pair<String, String>(getString(R.string.ignore_optimizations_off), getString(R.string.ignore_optimizations_off_desc))); mSelectedIndex = mBackend.isWhitelisted(mPackageName) ? 0 : 1; if (mBackend.isSysWhitelisted(mPackageName)) { mAdapter.setEnabled(1, false); } } @Override protected boolean refreshUi() { mUsageSwitch.setEnabled(!mBackend.isSysWhitelisted(mPackageName)); mUsageSwitch.setChecked(mBackend.isWhitelisted(mPackageName)); return true; public Dialog onCreateDialog(Bundle savedInstanceState) { AlertDialog.Builder b = new AlertDialog.Builder(getContext()) .setTitle(getString(R.string.ignore_optimizations_title, mLabel)) .setNegativeButton(R.string.cancel, null) .setSingleChoiceItems(mAdapter, mSelectedIndex, this); if (!mBackend.isSysWhitelisted(mPackageName)) { b.setPositiveButton(R.string.done, this); } return b.create(); } @Override public boolean onPreferenceChange(Preference preference, Object newValue) { if (newValue == Boolean.TRUE) { public void onClick(DialogInterface dialog, int which) { if (which == DialogInterface.BUTTON_POSITIVE) { boolean newValue = mSelectedIndex == 0; boolean oldValue = mBackend.isWhitelisted(mPackageName); if (newValue != oldValue) { if (newValue) { mBackend.addApp(mPackageName); } else { mBackend.removeApp(mPackageName); } return true; } @Override protected AlertDialog createDialog(int id, int errorCode) { return null; } else { mSelectedIndex = which; } @Override protected int getMetricsCategory() { return MetricsLogger.FUELGAUGE_HIGH_POWER_DETAILS; } public static CharSequence getSummary(Context context, AppEntry entry) { Loading @@ -81,4 +106,36 @@ public class HighPowerDetail extends AppInfoWithHeader implements OnPreferenceCh ? R.string.high_power_on : R.string.high_power_off); } public static void show(Activity activity, String packageName) { HighPowerDetail fragment = new HighPowerDetail(); Bundle args = new Bundle(); args.putString(AppInfoBase.ARG_PACKAGE_NAME, packageName); fragment.setArguments(args); fragment.show(activity.getFragmentManager(), HighPowerDetail.class.getSimpleName()); } private class Adapter extends ArrayAdapter<Pair<String, String>> { private final SparseBooleanArray mEnabled = new SparseBooleanArray(); public Adapter(Context context, int resource) { super(context, resource, android.R.id.title); } public void setEnabled(int index, boolean enabled) { mEnabled.put(index, enabled); } public boolean isEnabled(int position) { return mEnabled.get(position, true); } @Override public View getView(int position, View convertView, ViewGroup parent) { View view = super.getView(position, convertView, parent); ((TextView) view.findViewById(android.R.id.title)).setText(getItem(position).first); ((TextView) view.findViewById(android.R.id.summary)).setText(getItem(position).second); view.setEnabled(isEnabled(position)); return view; } } } Loading
AndroidManifest.xml +5 −0 Original line number Diff line number Diff line Loading @@ -944,6 +944,11 @@ <activity android:name="Settings$HighPowerApplicationsActivity" android:label="@string/high_power_apps" android:taskAffinity=""> <intent-filter android:priority="1"> <action android:name="android.settings.IGNORE_BATTERY_OPTIMIZATION_SETTINGS" /> <category android:name="android.intent.category.DEFAULT" /> <data android:scheme="package" /> </intent-filter> <meta-data android:name="com.android.settings.FRAGMENT_CLASS" android:value="com.android.settings.applications.ManageApplications" /> <meta-data android:name="com.android.settings.PRIMARY_PROFILE_CONTROLLED" Loading
res/layout/radio_with_summary.xml 0 → 100644 +47 −0 Original line number Diff line number Diff line <?xml version="1.0" encoding="utf-8"?> <!-- Copyright (C) 2015 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. --> <com.android.settings.CheckableLinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:minHeight="?android:attr/listPreferredItemHeightSmall"> <CheckedTextView android:id="@android:id/title" android:layout_width="match_parent" android:layout_height="wrap_content" android:textAppearance="?android:attr/textAppearanceMedium" android:textColor="?android:attr/textColorAlertDialogListItem" android:gravity="center_vertical" android:paddingStart="20dp" android:paddingEnd="?android:attr/dialogPreferredPadding" android:drawableStart="?android:attr/listChoiceIndicatorSingle" android:ellipsize="marquee" /> <TextView android:id="@+android:id/summary" android:layout_width="match_parent" android:layout_height="wrap_content" android:paddingBottom="4dp" android:paddingStart="52dp" android:textAppearance="?android:attr/textAppearanceListItemSecondary" android:textColor="?android:attr/textColorSecondary" android:maxLines="10" /> </com.android.settings.CheckableLinearLayout>
src/com/android/settings/CheckableLinearLayout.java 0 → 100644 +72 −0 Original line number Diff line number Diff line /* * Copyright (C) 2015 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.content.Context; import android.util.AttributeSet; import android.util.TypedValue; import android.view.View; import android.widget.Checkable; import android.widget.LinearLayout; public class CheckableLinearLayout extends LinearLayout implements Checkable { private boolean mChecked; private float mDisabledAlpha; public CheckableLinearLayout(Context context, AttributeSet attrs) { super(context, attrs); TypedValue alpha = new TypedValue(); context.getTheme().resolveAttribute(android.R.attr.disabledAlpha, alpha, true); mDisabledAlpha = alpha.getFloat(); } @Override public void setEnabled(boolean enabled) { super.setEnabled(enabled); final int N = getChildCount(); for (int i = 0; i < N; i++) { getChildAt(i).setAlpha(enabled ? 1 : mDisabledAlpha); } } @Override public void setChecked(boolean checked) { mChecked = checked; updateChecked(); } @Override public boolean isChecked() { return mChecked; } @Override public void toggle() { setChecked(!mChecked); } private void updateChecked() { final int N = getChildCount(); for (int i = 0; i < N; i++) { View child = getChildAt(i); if (child instanceof Checkable) { ((Checkable) child).setChecked(mChecked); } } } }
src/com/android/settings/applications/ManageApplications.java +11 −1 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ import android.os.Environment; import android.os.UserHandle; import android.os.UserManager; import android.preference.PreferenceFrameLayout; import android.provider.Settings; import android.util.ArraySet; import android.util.Log; import android.view.LayoutInflater; Loading Loading @@ -239,6 +240,15 @@ public class ManageApplications extends InstrumentedFragment mListType = LIST_TYPE_HIGH_POWER; // Default to showing system. mShowSystem = true; if (intent != null && Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS .equals(intent.getAction())) { mCurrentPkgName = intent.getData().getSchemeSpecificPart(); if (mCurrentPkgName != null) { mCurrentUid = mApplicationsState.getEntry(mCurrentPkgName, UserHandle.myUserId()).info.uid; startApplicationDetailsActivity(); } } } else { mListType = LIST_TYPE_MAIN; } Loading Loading @@ -440,7 +450,7 @@ public class ManageApplications extends InstrumentedFragment startAppInfoFragment(AppStorageSettings.class, R.string.storage_settings); break; case LIST_TYPE_HIGH_POWER: startAppInfoFragment(HighPowerDetail.class, R.string.high_power_apps); HighPowerDetail.show(getActivity(), mCurrentPkgName); break; // TODO: Figure out if there is a way where we can spin up the profile's settings // process ahead of time, to avoid a long load of data when user clicks on a managed app. Loading
src/com/android/settings/fuelgauge/HighPowerDetail.java +88 −31 Original line number Diff line number Diff line Loading @@ -16,60 +16,85 @@ package com.android.settings.fuelgauge; import android.app.Activity; import android.app.AlertDialog; import android.app.Dialog; import android.app.DialogFragment; import android.content.Context; import android.content.DialogInterface; import android.content.DialogInterface.OnClickListener; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.os.Bundle; import android.preference.Preference; import android.preference.Preference.OnPreferenceChangeListener; import android.preference.SwitchPreference; import android.util.Pair; import android.util.SparseBooleanArray; import android.view.View; import android.view.ViewGroup; import android.widget.ArrayAdapter; import android.widget.TextView; import com.android.internal.logging.MetricsLogger; import com.android.settings.R; import com.android.settings.applications.AppInfoWithHeader; import com.android.settings.applications.AppInfoBase; import com.android.settingslib.applications.ApplicationsState.AppEntry; public class HighPowerDetail extends AppInfoWithHeader implements OnPreferenceChangeListener { private static final String KEY_HIGH_POWER_SWITCH = "high_power_switch"; public class HighPowerDetail extends DialogFragment implements OnClickListener { private final PowerWhitelistBackend mBackend = PowerWhitelistBackend.getInstance(); private SwitchPreference mUsageSwitch; private String mPackageName; private CharSequence mLabel; private Adapter mAdapter; private int mSelectedIndex; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); addPreferencesFromResource(R.xml.high_power_details); mUsageSwitch = (SwitchPreference) findPreference(KEY_HIGH_POWER_SWITCH); mUsageSwitch.setOnPreferenceChangeListener(this); mPackageName = getArguments().getString(AppInfoBase.ARG_PACKAGE_NAME); PackageManager pm = getContext().getPackageManager(); try { mLabel = pm.getApplicationInfo(mPackageName, 0).loadLabel(pm); } catch (NameNotFoundException e) { mLabel = mPackageName; } mAdapter = new Adapter(getContext(), R.layout.radio_with_summary); mAdapter.add(new Pair<String, String>(getString(R.string.ignore_optimizations_on), getString(R.string.ignore_optimizations_on_desc))); mAdapter.add(new Pair<String, String>(getString(R.string.ignore_optimizations_off), getString(R.string.ignore_optimizations_off_desc))); mSelectedIndex = mBackend.isWhitelisted(mPackageName) ? 0 : 1; if (mBackend.isSysWhitelisted(mPackageName)) { mAdapter.setEnabled(1, false); } } @Override protected boolean refreshUi() { mUsageSwitch.setEnabled(!mBackend.isSysWhitelisted(mPackageName)); mUsageSwitch.setChecked(mBackend.isWhitelisted(mPackageName)); return true; public Dialog onCreateDialog(Bundle savedInstanceState) { AlertDialog.Builder b = new AlertDialog.Builder(getContext()) .setTitle(getString(R.string.ignore_optimizations_title, mLabel)) .setNegativeButton(R.string.cancel, null) .setSingleChoiceItems(mAdapter, mSelectedIndex, this); if (!mBackend.isSysWhitelisted(mPackageName)) { b.setPositiveButton(R.string.done, this); } return b.create(); } @Override public boolean onPreferenceChange(Preference preference, Object newValue) { if (newValue == Boolean.TRUE) { public void onClick(DialogInterface dialog, int which) { if (which == DialogInterface.BUTTON_POSITIVE) { boolean newValue = mSelectedIndex == 0; boolean oldValue = mBackend.isWhitelisted(mPackageName); if (newValue != oldValue) { if (newValue) { mBackend.addApp(mPackageName); } else { mBackend.removeApp(mPackageName); } return true; } @Override protected AlertDialog createDialog(int id, int errorCode) { return null; } else { mSelectedIndex = which; } @Override protected int getMetricsCategory() { return MetricsLogger.FUELGAUGE_HIGH_POWER_DETAILS; } public static CharSequence getSummary(Context context, AppEntry entry) { Loading @@ -81,4 +106,36 @@ public class HighPowerDetail extends AppInfoWithHeader implements OnPreferenceCh ? R.string.high_power_on : R.string.high_power_off); } public static void show(Activity activity, String packageName) { HighPowerDetail fragment = new HighPowerDetail(); Bundle args = new Bundle(); args.putString(AppInfoBase.ARG_PACKAGE_NAME, packageName); fragment.setArguments(args); fragment.show(activity.getFragmentManager(), HighPowerDetail.class.getSimpleName()); } private class Adapter extends ArrayAdapter<Pair<String, String>> { private final SparseBooleanArray mEnabled = new SparseBooleanArray(); public Adapter(Context context, int resource) { super(context, resource, android.R.id.title); } public void setEnabled(int index, boolean enabled) { mEnabled.put(index, enabled); } public boolean isEnabled(int position) { return mEnabled.get(position, true); } @Override public View getView(int position, View convertView, ViewGroup parent) { View view = super.getView(position, convertView, parent); ((TextView) view.findViewById(android.R.id.title)).setText(getItem(position).first); ((TextView) view.findViewById(android.R.id.summary)).setText(getItem(position).second); view.setEnabled(isEnabled(position)); return view; } } }