App-level notification configuration settings page.

New sub-page off of notification settings to ban/unban
apps and navigate to an app's notification configuration
activity (if configured).

Centralized all notification settings artifacts under a new
settings subpackage.

Bug: 13935172
Change-Id: I53b75c02f0091900734d17dc9217035d0df9b466
This commit is contained in:
John Spurlock
2014-04-08 14:08:21 -04:00
parent 7476f5b904
commit 4a35051565
22 changed files with 820 additions and 427 deletions

View File

@@ -564,7 +564,7 @@
<category android:name="com.android.settings.SHORTCUT" />
</intent-filter>
<meta-data android:name="com.android.settings.FRAGMENT_CLASS"
android:value="com.android.settings.ZenModeSettings" />
android:value="com.android.settings.notification.ZenModeSettings" />
<meta-data android:name="com.android.settings.TOP_LEVEL_HEADER_ID"
android:resource="@id/notification_settings" />
</activity>
@@ -772,7 +772,7 @@
<category android:name="com.android.settings.SHORTCUT" />
</intent-filter>
<meta-data android:name="com.android.settings.FRAGMENT_CLASS"
android:value="com.android.settings.NotificationStation" />
android:value="com.android.settings.notification.NotificationStation" />
</activity>
<!--
@@ -1690,7 +1690,7 @@
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<meta-data android:name="com.android.settings.FRAGMENT_CLASS"
android:value="com.android.settings.NotificationAccessSettings" />
android:value="com.android.settings.notification.NotificationAccessSettings" />
<meta-data android:name="com.android.settings.TOP_LEVEL_HEADER_ID"
android:resource="@id/security_settings" />
</activity>
@@ -1707,7 +1707,7 @@
<category android:name="com.android.settings.SHORTCUT" />
</intent-filter>
<meta-data android:name="com.android.settings.FRAGMENT_CLASS"
android:value="com.android.settings.NotificationSettings" />
android:value="com.android.settings.notification.NotificationSettings" />
<meta-data android:name="com.android.settings.TOP_LEVEL_HEADER_ID"
android:resource="@id/notification_settings" />
</activity>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 969 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

View File

@@ -18,67 +18,76 @@
android:layout_height="wrap_content" >
<RelativeLayout
android:layout_width="match_parent"
android:id="@android:id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toStartOf="@+id/divider"
>
android:layout_alignWithParentIfMissing="true"
android:layout_toStartOf="@+id/settings_divider"
android:background="?android:attr/listChoiceBackgroundIndicator" >
<ImageView
android:id="@android:id/icon"
android:layout_width="@android:dimen/app_icon_size"
android:layout_height="@android:dimen/app_icon_size"
android:layout_width="@dimen/notification_app_icon_size"
android:layout_height="@dimen/notification_app_icon_size"
android:layout_centerVertical="true"
android:layout_marginBottom="10dp"
android:layout_marginStart="0dp"
android:layout_marginEnd="6dp"
android:layout_marginTop="10dp"
android:contentDescription="@null"
android:maxHeight="@android:dimen/app_icon_size"
android:maxWidth="@android:dimen/app_icon_size"
android:scaleType="fitCenter" />
android:scaleType="center" />
<ImageView
android:id="@android:id/icon1"
android:layout_width="@dimen/notification_app_icon_badge_size"
android:layout_height="@dimen/notification_app_icon_badge_size"
android:layout_marginLeft="@dimen/notification_app_icon_badge_margin"
android:layout_marginTop="@dimen/notification_app_icon_badge_margin"
android:background="#bb8b0000"
android:contentDescription="@null" />
<ImageView
android:id="@android:id/icon2"
android:layout_width="@dimen/notification_app_icon_badge_size"
android:layout_height="@dimen/notification_app_icon_badge_size"
android:layout_alignBottom="@android:id/icon"
android:layout_alignEnd="@android:id/icon"
android:layout_marginBottom="@dimen/notification_app_icon_badge_margin"
android:layout_marginEnd="@dimen/notification_app_icon_badge_margin"
android:background="#bb006400"
android:contentDescription="@null" />
<TextView
android:id="@android:id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_toStartOf="@android:id/button1"
android:layout_toEndOf="@android:id/icon"
android:ellipsize="end"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textAlignment="viewStart"
android:labelFor="@android:id/button2" />
android:textAppearance="?android:attr/textAppearanceMedium" />
</RelativeLayout>
<!-- Divider -->
<ImageView
android:id="@id/divider"
android:layout_width="wrap_content"
android:layout_height="match_parent"
<View
android:id="@+id/settings_divider"
android:layout_width="1dp"
android:layout_height="@dimen/notification_app_settings_divider_height"
android:layout_centerVertical="true"
android:layout_toStartOf="@android:id/button2"
android:contentDescription="@null"
android:src="@drawable/nav_divider" />
<!-- Settings icon -->
android:background="?android:attr/listDivider" />
<ImageView
android:id="@android:id/button2"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_alignBottom="@android:id/widget_frame"
android:layout_width="@dimen/notification_app_icon_size"
android:layout_height="@dimen/notification_app_icon_size"
android:layout_alignParentEnd="true"
android:layout_alignTop="@android:id/widget_frame"
android:layout_centerVertical="true"
android:layout_margin="0dip"
android:background="?android:attr/selectableItemBackground"
android:background="?android:attr/listChoiceBackgroundIndicator"
android:contentDescription="@string/notification_app_settings_button"
android:padding="8dip"
android:clickable="true"
android:focusable="true"
android:src="@drawable/ic_bt_config" />
android:scaleType="center"
android:src="@drawable/ic_settings_generic" />
<View
android:id="@+id/row_divider"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?android:attr/listDivider" />
</RelativeLayout>

View File

@@ -0,0 +1,47 @@
<!--
Copyright (C) 2014 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.
-->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<ImageView
android:id="@android:id/icon"
android:layout_width="@dimen/notification_app_icon_size"
android:layout_height="@dimen/notification_app_icon_size"
android:contentDescription="@null"
android:scaleType="center" />
<TextView
android:id="@android:id/title"
android:layout_width="match_parent"
android:layout_height="@dimen/notification_app_icon_size"
android:layout_toEndOf="@android:id/icon"
android:ellipsize="end"
android:gravity="center_vertical"
android:singleLine="true"
android:textAlignment="viewStart"
android:textAppearance="?android:attr/textAppearanceLarge" />
<CheckBox
android:id="@android:id/button1"
android:layout_width="match_parent"
android:layout_height="@dimen/notification_app_icon_size"
android:layout_below="@android:id/icon"
android:layout_marginStart="@dimen/content_margin_left"
android:text="@string/app_notifications_dialog_show"
android:textAppearance="?android:attr/textAppearanceListItem" />
</RelativeLayout>

View File

@@ -0,0 +1,42 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2014 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="match_parent"
android:orientation="vertical" >
<ListView
android:id="@android:id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:divider="#0000"
android:dividerHeight="0px"
android:fastScrollAlwaysVisible="true"
android:fastScrollEnabled="true"
android:listSelector="#0000"
android:scrollbarStyle="outsideInset" />
<TextView
android:id="@android:id/empty"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="@string/loading_notification_apps"
android:textAppearance="?android:attr/textAppearanceMedium" />
</LinearLayout>

View File

@@ -0,0 +1,19 @@
<!--
Copyright (C) 2014 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.
-->
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
style="?android:attr/listSeparatorTextViewStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content" />

View File

@@ -1,115 +0,0 @@
<!--
Copyright (C) 2013 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.
-->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<!-- Dream selectable row (icon, caption, radio button) -->
<RelativeLayout
android:id="@android:id/widget_frame"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_toStartOf="@+id/divider"
android:background="?android:attr/selectableItemBackground" >
<!-- Dream icon -->
<ImageView
android:id="@+id/pkgicon"
android:layout_width="@*android:dimen/status_bar_icon_size"
android:layout_height="@*android:dimen/status_bar_icon_size"
android:layout_centerVertical="true"
android:layout_marginBottom="6dp"
android:layout_marginStart="0dp"
android:layout_marginEnd="6dp"
android:layout_marginTop="6dp"
android:contentDescription="@null"
android:maxHeight="@*android:dimen/status_bar_icon_size"
android:maxWidth="@*android:dimen/status_bar_icon_size"
android:scaleType="fitCenter" />
<ImageView
android:id="@android:id/icon"
android:layout_width="@*android:dimen/status_bar_icon_size"
android:layout_height="@*android:dimen/status_bar_icon_size"
android:layout_centerVertical="true"
android:layout_toEndOf="@id/pkgicon"
android:layout_marginBottom="6dp"
android:layout_marginStart="0dp"
android:layout_marginEnd="8dp"
android:layout_marginTop="6dp"
android:contentDescription="@null"
android:maxHeight="@*android:dimen/status_bar_icon_size"
android:maxWidth="@*android:dimen/status_bar_icon_size"
android:scaleType="fitCenter" />
<!-- Dream caption -->
<TextView
android:id="@android:id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_toStartOf="@android:id/button1"
android:layout_toEndOf="@android:id/icon"
android:ellipsize="end"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textAlignment="viewStart"
android:labelFor="@android:id/button2" />
<!-- Dream radio button -->
<!--<RadioButton
android:id="@android:id/button1"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:duplicateParentState="true"
android:clickable="false"
android:focusable="false" />-->
</RelativeLayout>
<!-- Divider -->
<ImageView
android:id="@id/divider"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_centerVertical="true"
android:layout_toStartOf="@android:id/button2"
android:contentDescription="@null"
android:src="@drawable/nav_divider" />
<!-- Settings icon -->
<ImageView
android:id="@android:id/button2"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_alignBottom="@android:id/widget_frame"
android:layout_alignParentEnd="true"
android:layout_alignTop="@android:id/widget_frame"
android:layout_centerVertical="true"
android:layout_margin="0dip"
android:background="?android:attr/selectableItemBackground"
android:contentDescription="@string/screensaver_settings_button"
android:padding="8dip"
android:src="@drawable/ic_bt_config" />
</RelativeLayout>

View File

@@ -33,7 +33,7 @@
android:layout_width="@*android:dimen/status_bar_icon_size"
android:layout_height="@*android:dimen/status_bar_icon_size"
android:layout_centerVertical="true"
android:layout_toEndOf="@id/pkgicon"
android:layout_toEndOf="@+id/pkgicon"
android:layout_marginStart="0dp"
android:layout_marginEnd="8dp"
android:contentDescription="@null"

View File

@@ -78,4 +78,9 @@
<integer name="preferences_left_pane_weight">4</integer>
<!-- Weight of the right pane in a multi-pane preference layout. So the split is 40:60 -->
<integer name="preferences_right_pane_weight">6</integer>
<dimen name="notification_app_icon_size">64dp</dimen>
<dimen name="notification_app_icon_badge_size">20dp</dimen>
<dimen name="notification_app_icon_badge_margin">4dp</dimen>
<dimen name="notification_app_settings_divider_height">48dp</dimen>
</resources>

View File

@@ -1767,9 +1767,7 @@
<!-- Sound settings screen, notification light repeat pulsing title -->
<string name="notification_pulse_title">Pulse notification light</string>
<!-- Display settings screen, notification popups are enabled [CHAR LIMIT=30] -->
<string name="heads_up_enabled_title">Heads Up Notifications</string>
<!-- Display settings screen, notification popups are explained [CHAR LIMIT=45]-->
<string name="heads_up_enabled_summary">Important notifications will pop up</string>
<string name="heads_up_enabled_title">Pop up if high priority</string>
<!-- Sound settings screen, the title of the volume bar to adjust the incoming call volume -->
<string name="incoming_call_volume_title">Ringtone</string>
<!-- Sound settings screen, the title of the volume bar to adjust the notification volume -->
@@ -5027,38 +5025,31 @@
<!-- Notifications on lockscreen -->
<!-- Label for checkbox controlling the contents of notifications shown on
the secure lockscreen [CHAR LIMIT=25] -->
<string name="lock_screen_notifications">Show when locked</string>
<string name="lock_screen_notifications">Show on lock screen</string>
<!-- Summary for lock_screen_notifications: sensitive information will be
hidden or redacted from notifications shown on a secure lock screen
[CHAR LIMIT=50] -->
<string name="lock_screen_notifications_summary_off">Sensitive notification contents will be hidden on the lock screen</string>
<string name="lock_screen_notifications_summary_off">Unless content is sensitive</string>
<!-- Summary for lock_screen_notifications: all information will be
shown in notifications shown on a secure lock screen
[CHAR LIMIT=50] -->
<string name="lock_screen_notifications_summary_on">All notification contents will be shown on the lock screen</string>
<string name="lock_screen_notifications_summary_on">All notifications</string>
<!-- [CHAR LIMIT=30] Notification settings screen, setting option name -->
<string name="title_zen_mode">Do not disturb</string>
<!-- [CHAR LIMIT=30] Sound settings screen, setting option name to change zen mode -->
<string name="title_zen_mode">Limited interruptions</string>
<!-- [CHAR LIMIT=30] Sound settings screen, description for configuring zen mode -->
<string name="configure_zen_mode_description">Configure limited interruptions</string>
<!-- [CHAR LIMIT=30] Zen mode settings screen, activity title -->
<string name="zen_mode_settings_title">Limited Interruptions</string>
<string name="zen_mode_settings_title">Do not disturb</string>
<!-- [CHAR LIMIT=20] Notifications settings header -->
<string name="notification_settings">Notifications</string>
<!-- [CHAR LIMIT=20] Notifications settings: General section header -->
<string name="notification_settings_general">General</string>
<!-- [CHAR LIMIT=20] Notifications settings: Security section header -->
<string name="notification_settings_security">Security</string>
<!-- [CHAR LIMIT=20] Notifications settings: Tweaks section header (eng
builds only) -->
<string name="notification_settings_tweaks">Tweaks</string>
<!-- [CHAR LIMIT=20] Notifications settings: Apps section header -->
<string name="notification_settings_apps">Apps</string>
<string name="notification_settings_apps_title">App notifications</string>
<!-- [CHAR LIMIT=NONE] Content description for per-app notification
settings button -->
@@ -5081,5 +5072,21 @@
<!-- Text displayed when tag is not writable -->
<string name="status_tag_not_writable">NFC tag is not writable. Please use a different tag.</string>
<!-- Option title for the default sound, context based on screen -->
<string name="default_sound">Default sound</string>
<!-- [CHAR LIMIT=NONE] Text when loading app list in notification settings -->
<string name="loading_notification_apps">Loading apps...</string>
<!-- [CHAR LIMIT=40] Notification settings: App notifications screen title -->
<string name="app_notifications_title">App notifications</string>
<!-- [CHAR LIMIT=30] Notification settings: App notifications dialog show option -->
<string name="app_notifications_dialog_show">Show notifications</string>
<!-- [CHAR LIMIT=30] Notification settings: App notifications dialog priority option -->
<string name="app_notifications_dialog_priority">High priority</string>
<!-- [CHAR LIMIT=20] Notification settings: App notifications dialog dismiss button caption -->
<string name="app_notifications_dialog_done">Done</string>
</resources>

View File

@@ -19,13 +19,9 @@
android:key="notification_settings"
xmlns:settings="http://schemas.android.com/apk/res/com.android.settings">
<PreferenceCategory
android:key="category_general"
android:title="@string/notification_settings_general">
<com.android.settings.DefaultRingtonePreference
android:key="notification_sound"
android:title="@string/notification_sound_title"
android:title="@string/default_sound"
android:dialogTitle="@string/notification_sound_dialog_title"
android:persistent="false"
android:ringtoneType="notification" />
@@ -38,20 +34,8 @@
<CheckBoxPreference
android:key="heads_up"
android:title="@string/heads_up_enabled_title"
android:summary="@string/heads_up_enabled_summary"
android:persistent="false" />
<PreferenceScreen
android:key="zen_mode"
android:title="@string/title_zen_mode"
android:fragment="com.android.settings.ZenModeSettings" />
</PreferenceCategory>
<PreferenceCategory
android:key="category_security"
android:title="@string/notification_settings_security">
<CheckBoxPreference
android:key="toggle_lock_screen_notifications"
android:title="@string/lock_screen_notifications"
@@ -59,27 +43,20 @@
android:summaryOn="@string/lock_screen_notifications_summary_on"
android:persistent="false" />
<PreferenceScreen
android:key="configure"
android:title="@string/notification_settings_apps_title"
android:fragment="com.android.settings.notification.AppNotificationSettings" />
<PreferenceScreen
android:key="zen_mode"
android:title="@string/title_zen_mode"
android:fragment="com.android.settings.notification.ZenModeSettings" />
<Preference
android:key="manage_notification_access"
android:title="@string/manage_notification_access"
android:persistent="false"
android:fragment="com.android.settings.NotificationAccessSettings"/>
</PreferenceCategory>
<!--
<PreferenceCategory
android:key="category_tweaks"
android:title="@string/notification_settings_tweaks"/>
<Preference
android:title="Coming soon"
/>
-->
<PreferenceCategory
android:key="category_apps"
android:title="@string/notification_settings_apps">
</PreferenceCategory>
android:fragment="com.android.settings.notification.NotificationAccessSettings" />
</PreferenceScreen>

View File

@@ -85,7 +85,7 @@
<header
android:id="@+id/notification_settings"
android:icon="@drawable/ic_settings_notifications"
android:fragment="com.android.settings.NotificationSettings"
android:fragment="com.android.settings.notification.NotificationSettings"
android:title="@string/notification_settings" />
<!-- Storage -->

View File

@@ -93,6 +93,10 @@ import com.android.settings.inputmethod.UserDictionaryList;
import com.android.settings.location.LocationSettings;
import com.android.settings.nfc.AndroidBeam;
import com.android.settings.nfc.PaymentSettings;
import com.android.settings.notification.NotificationAccessSettings;
import com.android.settings.notification.NotificationSettings;
import com.android.settings.notification.NotificationStation;
import com.android.settings.notification.ZenModeSettings;
import com.android.settings.print.PrintJobSettingsFragment;
import com.android.settings.print.PrintSettingsFragment;
import com.android.settings.tts.TextToSpeechSettings;

View File

@@ -0,0 +1,550 @@
/*
* Copyright (C) 2014 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.notification;
import android.animation.LayoutTransition;
import android.app.AlertDialog;
import android.app.INotificationManager;
import android.app.ListFragment;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
import android.content.pm.Signature;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.shapes.PathShape;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.Parcelable;
import android.os.ServiceManager;
import android.os.SystemClock;
import android.util.ArrayMap;
import android.util.Log;
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.SectionIndexer;
import android.widget.TextView;
import com.android.settings.R;
import java.text.Collator;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class AppNotificationSettings extends ListFragment {
private static final String TAG = "AppNotificationSettings";
private static final boolean DEBUG = true;
private static final String SECTION_BEFORE_A = "*";
private static final String SECTION_AFTER_Z = "**";
private static final Intent APP_NOTIFICATION_PREFS_CATEGORY_INTENT
= new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_NOTIFICATION_PREFERENCES);
private final Handler mHandler = new Handler();
private final ArrayMap<String, AppRow> mRows = new ArrayMap<String, AppRow>();
private final ArrayList<AppRow> mSortedRows = new ArrayList<AppRow>();
private final ArrayList<String> mSections = new ArrayList<String>();
private Context mContext;
private LayoutInflater mInflater;
private NotificationAppAdapter mAdapter;
private Signature[] mSystemSignature;
private Parcelable mListViewState;
private Backend mBackend = new Backend();
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mContext = getActivity();
mInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mAdapter = new NotificationAppAdapter(mContext);
getActivity().setTitle(R.string.app_notifications_title);
}
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.notification_app_list, container, false);
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
repositionScrollbar();
getListView().setAdapter(mAdapter);
}
@Override
public void onPause() {
super.onPause();
if (DEBUG) Log.d(TAG, "Saving listView state");
mListViewState = getListView().onSaveInstanceState();
}
@Override
public void onResume() {
super.onResume();
loadAppsList();
}
public void setBackend(Backend backend) {
mBackend = backend;
}
private void loadAppsList() {
AsyncTask.execute(mCollectAppsRunnable);
}
private String getSection(CharSequence label) {
if (label == null || label.length() == 0) return SECTION_BEFORE_A;
final char c = Character.toUpperCase(label.charAt(0));
if (c < 'A') return SECTION_BEFORE_A;
if (c > 'Z') return SECTION_AFTER_Z;
return Character.toString(c);
}
private void repositionScrollbar() {
final int sbWidthPx = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
getListView().getScrollBarSize(),
getResources().getDisplayMetrics());
final View parent = (View)getView().getParent();
final int eat = Math.min(sbWidthPx, parent.getPaddingEnd());
if (eat <= 0) return;
if (DEBUG) Log.d(TAG, String.format("Eating %dpx into %dpx padding for %dpx scroll, ld=%d",
eat, parent.getPaddingEnd(), sbWidthPx, getListView().getLayoutDirection()));
parent.setPaddingRelative(parent.getPaddingStart(), parent.getPaddingTop(),
parent.getPaddingEnd() - eat, parent.getPaddingBottom());
}
private boolean isSystemApp(PackageInfo pkg) {
if (mSystemSignature == null) {
mSystemSignature = new Signature[]{ getSystemSignature() };
}
return mSystemSignature[0] != null && mSystemSignature[0].equals(getFirstSignature(pkg));
}
private static Signature getFirstSignature(PackageInfo pkg) {
if (pkg != null && pkg.signatures != null && pkg.signatures.length > 0) {
return pkg.signatures[0];
}
return null;
}
private Signature getSystemSignature() {
final PackageManager pm = mContext.getPackageManager();
try {
final PackageInfo sys = pm.getPackageInfo("android", PackageManager.GET_SIGNATURES);
return getFirstSignature(sys);
} catch (NameNotFoundException e) {
}
return null;
}
private void showDialog(final View v, final AppRow row) {
final RelativeLayout layout = (RelativeLayout)
mInflater.inflate(R.layout.notification_app_dialog, null);
final ImageView icon = (ImageView) layout.findViewById(android.R.id.icon);
icon.setImageDrawable(row.icon);
final TextView title = (TextView) layout.findViewById(android.R.id.title);
title.setText(row.label);
final CheckBox showBox = (CheckBox) layout.findViewById(android.R.id.button1);
showBox.setChecked(!row.banned);
final OnCheckedChangeListener showListener = new OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
boolean success = mBackend.setNotificationsBanned(row.pkg, row.uid, !isChecked);
if (success) {
row.banned = !isChecked;
mAdapter.bindView(v, row, true /*animate*/);
} else {
showBox.setOnCheckedChangeListener(null);
showBox.setChecked(!isChecked);
showBox.setOnCheckedChangeListener(this);
}
}
};
showBox.setOnCheckedChangeListener(showListener);
final AlertDialog d = new AlertDialog.Builder(mContext)
.setView(layout)
.setPositiveButton(R.string.app_notifications_dialog_done, null)
.create();
d.show();
}
private static class ViewHolder {
ViewGroup row;
ViewGroup appButton;
ImageView icon;
ImageView banBadge;
ImageView priBadge;
TextView title;
View settingsDivider;
ImageView settingsButton;
View rowDivider;
}
private class NotificationAppAdapter extends ArrayAdapter<Row> implements SectionIndexer {
private final ShapeDrawable mBanShape, mPriShape;
public NotificationAppAdapter(Context context) {
super(context, 0, 0);
final int s = context.getResources()
.getDimensionPixelSize(R.dimen.notification_app_icon_badge_size);
mBanShape = shape(banPath(s), s);
mPriShape = shape(priPath(s), s);
}
private ShapeDrawable shape(Path path, int s) {
final ShapeDrawable sd = new ShapeDrawable(new PathShape(path, s, s));
sd.getPaint().setStyle(Paint.Style.STROKE);
sd.getPaint().setColor(0xffffffff);
sd.getPaint().setStrokeWidth(s / 12);
sd.setIntrinsicWidth(s);
sd.setIntrinsicHeight(s);
return sd;
}
private Path banPath(int s) {
final Path p = new Path();
final int d = s / 5;
p.moveTo(d, d); p.lineTo(s - d, s - d);
p.moveTo(d, s - d); p.lineTo(s - d, d);
return p;
}
private Path priPath(int s) {
final Path p = new Path();
final int d = s / 5;
p.moveTo(s / 2, d); p.lineTo(s / 2, s - d);
return p;
}
@Override
public boolean hasStableIds() {
return true;
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public int getViewTypeCount() {
return 2;
}
@Override
public int getItemViewType(int position) {
Row r = getItem(position);
return r instanceof AppRow ? 1 : 0;
}
public View getView(int position, View convertView, ViewGroup parent) {
Row r = getItem(position);
View v;
if (convertView == null) {
v = newView(parent, r);
} else {
v = convertView;
}
bindView(v, r, false /*animate*/);
return v;
}
public View newView(ViewGroup parent, Row r) {
if (!(r instanceof AppRow)) {
return mInflater.inflate(R.layout.notification_app_section, parent, false);
}
final View v = mInflater.inflate(R.layout.notification_app, parent, false);
final ViewHolder vh = new ViewHolder();
vh.row = (ViewGroup) v;
vh.row.setLayoutTransition(new LayoutTransition());
vh.appButton = (ViewGroup) v.findViewById(android.R.id.button1);
vh.appButton.setLayoutTransition(new LayoutTransition());
vh.icon = (ImageView) v.findViewById(android.R.id.icon);
vh.banBadge = (ImageView) v.findViewById(android.R.id.icon1);
vh.banBadge.setImageDrawable(mBanShape);
vh.priBadge = (ImageView) v.findViewById(android.R.id.icon2);
vh.priBadge.setImageDrawable(mPriShape);
vh.title = (TextView) v.findViewById(android.R.id.title);
vh.settingsDivider = v.findViewById(R.id.settings_divider);
vh.settingsButton = (ImageView) v.findViewById(android.R.id.button2);
vh.rowDivider = v.findViewById(R.id.row_divider);
v.setTag(vh);
return v;
}
private void enableLayoutTransitions(ViewGroup vg, boolean enabled) {
if (enabled) {
vg.getLayoutTransition().enableTransitionType(LayoutTransition.APPEARING);
vg.getLayoutTransition().enableTransitionType(LayoutTransition.DISAPPEARING);
} else {
vg.getLayoutTransition().disableTransitionType(LayoutTransition.APPEARING);
vg.getLayoutTransition().disableTransitionType(LayoutTransition.DISAPPEARING);
}
}
public void bindView(final View view, Row r, boolean animate) {
if (!(r instanceof AppRow)) {
TextView tv = (TextView)view;
tv.setText(r.section);
return;
}
final AppRow row = (AppRow)r;
final ViewHolder vh = (ViewHolder) view.getTag();
enableLayoutTransitions(vh.row, animate);
vh.rowDivider.setVisibility(row.first ? View.GONE : View.VISIBLE);
vh.appButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
showDialog(view, row);
}
});
enableLayoutTransitions(vh.appButton, animate);
vh.icon.setImageDrawable(row.icon);
vh.banBadge.setVisibility(row.banned ? View.VISIBLE : View.GONE);
vh.priBadge.setVisibility(row.priority ? View.VISIBLE : View.GONE);
vh.title.setText(row.label);
final boolean showSettings = !row.banned && row.settingsIntent != null;
vh.settingsDivider.setVisibility(showSettings ? View.VISIBLE : View.GONE);
vh.settingsButton.setVisibility(showSettings ? View.VISIBLE : View.GONE);
vh.settingsButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (row.settingsIntent != null) {
getContext().startActivity(row.settingsIntent);
}
}
});
}
@Override
public Object[] getSections() {
return mSections.toArray(new Object[mSections.size()]);
}
@Override
public int getPositionForSection(int sectionIndex) {
final String section = mSections.get(sectionIndex);
final int n = getCount();
for (int i = 0; i < n; i++) {
final Row r = getItem(i);
if (r.section.equals(section)) {
return i;
}
}
return 0;
}
@Override
public int getSectionForPosition(int position) {
Row row = getItem(position);
return mSections.indexOf(row.section);
}
}
private static class Row {
public String section;
}
private static class AppRow extends Row {
public String pkg;
public int uid;
public Drawable icon;
public CharSequence label;
public Intent settingsIntent;
public boolean banned;
public boolean priority;
public boolean first;
}
private static final Comparator<AppRow> mRowComparator = new Comparator<AppRow>() {
private final Collator sCollator = Collator.getInstance();
@Override
public int compare(AppRow lhs, AppRow rhs) {
return sCollator.compare(lhs.label, rhs.label);
}
};
private final Runnable mCollectAppsRunnable = new Runnable() {
@Override
public void run() {
synchronized (mRows) {
final long start = SystemClock.uptimeMillis();
if (DEBUG) Log.d(TAG, "Collecting apps...");
mRows.clear();
mSortedRows.clear();
// collect all non-system apps
final PackageManager pm = mContext.getPackageManager();
for (PackageInfo pkg : pm.getInstalledPackages(PackageManager.GET_SIGNATURES)) {
if (pkg.applicationInfo == null || isSystemApp(pkg)) {
if (DEBUG) Log.d(TAG, "Skipping " + pkg.packageName);
continue;
}
final AppRow row = new AppRow();
row.pkg = pkg.packageName;
row.uid = pkg.applicationInfo.uid;
try {
row.label = pkg.applicationInfo.loadLabel(pm);
} catch (Throwable t) {
Log.e(TAG, "Error loading application label for " + row.pkg, t);
row.label = row.pkg;
}
row.icon = pkg.applicationInfo.loadIcon(pm);
row.banned = mBackend.getNotificationsBanned(row.pkg, row.uid);
row.priority = mBackend.getHighPriority(row.pkg, row.uid);
mRows.put(row.pkg, row);
}
// collect config activities
Log.d(TAG, "APP_NOTIFICATION_PREFS_CATEGORY_INTENT is " + APP_NOTIFICATION_PREFS_CATEGORY_INTENT);
final List<ResolveInfo> resolveInfos = pm.queryIntentActivities(
APP_NOTIFICATION_PREFS_CATEGORY_INTENT,
PackageManager.MATCH_DEFAULT_ONLY);
if (DEBUG) Log.d(TAG, "Found " + resolveInfos.size() + " preference activities");
for (ResolveInfo ri : resolveInfos) {
final ActivityInfo activityInfo = ri.activityInfo;
final ApplicationInfo appInfo = activityInfo.applicationInfo;
final AppRow row = mRows.get(appInfo.packageName);
if (row == null) {
Log.v(TAG, "Ignoring notification preference activity ("
+ activityInfo.name + ") for unknown package "
+ activityInfo.packageName);
continue;
}
if (row.settingsIntent != null) {
Log.v(TAG, "Ignoring duplicate notification preference activity ("
+ activityInfo.name + ") for package "
+ activityInfo.packageName);
continue;
}
row.settingsIntent = new Intent(Intent.ACTION_MAIN)
.setClassName(activityInfo.packageName, activityInfo.name);
}
// sort rows
mSortedRows.addAll(mRows.values());
Collections.sort(mSortedRows, mRowComparator);
// compute sections
mSections.clear();
String section = null;
for (AppRow r : mSortedRows) {
r.section = getSection(r.label);
if (!r.section.equals(section)) {
section = r.section;
mSections.add(section);
}
}
mHandler.post(mRefreshAppsListRunnable);
final long elapsed = SystemClock.uptimeMillis() - start;
if (DEBUG) Log.d(TAG, "Collected " + mRows.size() + " apps in " + elapsed + "ms");
}
}
};
private void refreshDisplayedItems() {
if (DEBUG) Log.d(TAG, "Refreshing apps...");
mAdapter.clear();
synchronized (mSortedRows) {
String section = null;
final int N = mSortedRows.size();
boolean first = true;
for (int i = 0; i < N; i++) {
final AppRow row = mSortedRows.get(i);
if (!row.section.equals(section)) {
section = row.section;
Row r = new Row();
r.section = section;
mAdapter.add(r);
first = true;
}
row.first = first;
mAdapter.add(row);
first = false;
}
}
if (mListViewState != null) {
if (DEBUG) Log.d(TAG, "Restoring listView state");
getListView().onRestoreInstanceState(mListViewState);
mListViewState = null;
}
if (DEBUG) Log.d(TAG, "Refreshed " + mSortedRows.size() + " displayed items");
}
private final Runnable mRefreshAppsListRunnable = new Runnable() {
@Override
public void run() {
refreshDisplayedItems();
}
};
public static class Backend {
public boolean setNotificationsBanned(String pkg, int uid, boolean banned) {
INotificationManager nm = INotificationManager.Stub.asInterface(
ServiceManager.getService(Context.NOTIFICATION_SERVICE));
try {
nm.setNotificationsEnabledForPackage(pkg, uid, !banned);
return true;
} catch (Exception e) {
Log.w(TAG, "Error calling NoMan", e);
return false;
}
}
public boolean getNotificationsBanned(String pkg, int uid) {
INotificationManager nm = INotificationManager.Stub.asInterface(
ServiceManager.getService(Context.NOTIFICATION_SERVICE));
try {
final boolean enabled = nm.areNotificationsEnabledForPackage(pkg, uid);
return !enabled;
} catch (Exception e) {
Log.w(TAG, "Error calling NoMan", e);
return false;
}
}
public boolean getHighPriority(String pkg, int uid) {
// TODO get high-pri state from NoMan
return false;
}
public boolean setHighPriority(String pkg, int uid, boolean priority) {
// TODO save high-pri state to NoMan
return true;
}
}
}

View File

@@ -14,41 +14,42 @@
* limitations under the License.
*/
package com.android.settings;
package com.android.settings.notification;
import android.app.ActivityManager;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.DialogFragment;
import android.app.ListFragment;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageItemInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.provider.Settings;
import android.service.notification.NotificationListenerService;
import android.util.Slog;
import android.widget.ArrayAdapter;
import android.app.ListFragment;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.Bundle;
import android.provider.Settings;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.CheckBox;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import com.android.settings.R;
import java.util.HashSet;
import java.util.List;

View File

@@ -14,57 +14,40 @@
* limitations under the License.
*/
package com.android.settings;
package com.android.settings.notification;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.database.ContentObserver;
import android.graphics.drawable.Drawable;
import android.media.RingtoneManager;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.preference.CheckBoxPreference;
import android.preference.Preference;
import android.preference.Preference.OnPreferenceClickListener;
import android.preference.PreferenceGroup;
import android.preference.PreferenceScreen;
import android.preference.TwoStatePreference;
import android.provider.Settings;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import java.text.Collator;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import com.android.settings.R;
import com.android.settings.SettingsPreferenceFragment;
import com.android.settings.SoundSettings;
public class NotificationSettings extends SettingsPreferenceFragment implements
Preference.OnPreferenceChangeListener, OnPreferenceClickListener {
private static final String TAG = "NotificationSettings";
private static final Intent APP_NOTIFICATION_PREFS_CATEGORY_INTENT
= new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_NOTIFICATION_PREFERENCES);
private static final String KEY_NOTIFICATION_SOUND = "notification_sound";
private static final String KEY_NOTIFICATION_ACCESS = "manage_notification_access";
private static final String KEY_LOCK_SCREEN_NOTIFICATIONS = "toggle_lock_screen_notifications";
private static final String KEY_HEADS_UP = "heads_up";
private static final String KEY_NOTIFICATION_PULSE = "notification_pulse";
private static final String KEY_HEADS_UP = "heads_up";
private static final String KEY_LOCK_SCREEN_NOTIFICATIONS = "toggle_lock_screen_notifications";
private static final String KEY_NOTIFICATION_ACCESS = "manage_notification_access";
private static final String KEY_SECURITY_CATEGORY = "category_security";
private static final String KEY_APPS_CATEGORY = "category_apps";
private static final String KEY_TWEAKS_CATEGORY = "category_tweaks"; // power toys, eng only
private static final int MSG_UPDATE_SOUND_SUMMARY = 2;
@@ -74,10 +57,9 @@ public class NotificationSettings extends SettingsPreferenceFragment implements
private Preference mNotificationSoundPreference;
private Preference mNotificationAccess;
private CheckBoxPreference mLockscreenNotifications;
private CheckBoxPreference mHeadsUp;
private CheckBoxPreference mNotificationPulse;
private PreferenceGroup mAppsPreference;
private TwoStatePreference mLockscreenNotifications;
private TwoStatePreference mHeadsUp;
private TwoStatePreference mNotificationPulse;
private final Runnable mRingtoneLookupRunnable = new Runnable() {
@Override
@@ -104,80 +86,6 @@ public class NotificationSettings extends SettingsPreferenceFragment implements
}
};
private final ArrayList<AppNotificationInfo> mAppNotificationInfo
= new ArrayList<AppNotificationInfo>();
private final HashSet<String> mAppNotificationInfoPackages = new HashSet<String>();
private final Comparator<AppNotificationInfo> mAppComparator = new Comparator<AppNotificationInfo>() {
private final Collator sCollator = Collator.getInstance();
@Override
public int compare(AppNotificationInfo lhs, AppNotificationInfo rhs) {
return sCollator.compare(lhs.label, rhs.label);
}
};
private final Runnable mCollectAppsRunnable = new Runnable() {
@Override
public void run() {
synchronized (mAppNotificationInfo) {
mAppNotificationInfo.clear();
mAppNotificationInfoPackages.clear();
final PackageManager pm = getPackageManager();
final List<ResolveInfo> resolveInfos = pm.queryIntentActivities(APP_NOTIFICATION_PREFS_CATEGORY_INTENT,
PackageManager.MATCH_DEFAULT_ONLY);
for (ResolveInfo ri : resolveInfos) {
final ActivityInfo activityInfo = ri.activityInfo;
final ApplicationInfo appInfo = activityInfo.applicationInfo;
if (mAppNotificationInfoPackages.contains(activityInfo.packageName)) {
Log.v(TAG, "Ignoring duplicate notification preference activity ("
+ activityInfo.name + ") for package "
+ activityInfo.packageName);
continue;
}
final AppNotificationInfo info = new AppNotificationInfo();
mAppNotificationInfoPackages.add(activityInfo.packageName);
info.label = appInfo.loadLabel(pm);
info.icon = appInfo.loadIcon(pm);
info.name = activityInfo.name;
info.pkg = activityInfo.packageName;
mAppNotificationInfo.add(info);
}
Collections.sort(mAppNotificationInfo, mAppComparator);
mHandler.post(mRefreshAppsListRunnable);
}
}
};
private final Runnable mRefreshAppsListRunnable = new Runnable() {
@Override
public void run() {
synchronized (mAppNotificationInfo) {
mAppsPreference.removeAll();
Preference p = getPreferenceScreen().findPreference(mAppsPreference.getKey());
final int N = mAppNotificationInfo.size();
if (N == 0 && p != null) {
getPreferenceScreen().removePreference(p);
} else if (N > 0 && p == null) {
getPreferenceScreen().addPreference(mAppsPreference);
}
for (int i = 0; i < N; i++) {
final AppNotificationInfo info = mAppNotificationInfo.get(i);
Preference pref = new AppNotificationPreference(mContext);
pref.setTitle(info.label);
pref.setIcon(info.icon);
pref.setIntent(new Intent(Intent.ACTION_MAIN)
.setClassName(info.pkg, info.name));
mAppsPreference.addPreference(pref);
}
}
}
};
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -189,8 +97,6 @@ public class NotificationSettings extends SettingsPreferenceFragment implements
addPreferencesFromResource(R.xml.notification_settings);
final PreferenceScreen root = getPreferenceScreen();
final PreferenceGroup securityCategory = (PreferenceGroup)
root.findPreference(KEY_SECURITY_CATEGORY);
PreferenceGroup tweaksCategory = (PreferenceGroup)
root.findPreference(KEY_TWEAKS_CATEGORY);
@@ -207,18 +113,16 @@ public class NotificationSettings extends SettingsPreferenceFragment implements
refreshNotificationListeners();
mLockscreenNotifications
= (CheckBoxPreference) root.findPreference(KEY_LOCK_SCREEN_NOTIFICATIONS);
= (TwoStatePreference) root.findPreference(KEY_LOCK_SCREEN_NOTIFICATIONS);
if (mLockscreenNotifications != null) {
if (!getDeviceLockscreenNotificationsEnabled()) {
if (securityCategory != null) {
securityCategory.removePreference(mLockscreenNotifications);
}
root.removePreference(mLockscreenNotifications);
} else {
mLockscreenNotifications.setChecked(getLockscreenAllowPrivateNotifications());
}
}
mHeadsUp = (CheckBoxPreference) findPreference(KEY_HEADS_UP);
mHeadsUp = (TwoStatePreference) findPreference(KEY_HEADS_UP);
if (mHeadsUp != null) {
updateHeadsUpMode(resolver);
mHeadsUp.setOnPreferenceChangeListener(this);
@@ -231,7 +135,7 @@ public class NotificationSettings extends SettingsPreferenceFragment implements
}
});
}
mNotificationPulse = (CheckBoxPreference) findPreference(KEY_NOTIFICATION_PULSE);
mNotificationPulse = (TwoStatePreference) findPreference(KEY_NOTIFICATION_PULSE);
if (mNotificationPulse != null
&& getResources().getBoolean(
@@ -246,8 +150,6 @@ public class NotificationSettings extends SettingsPreferenceFragment implements
Log.e(TAG, Settings.System.NOTIFICATION_LIGHT_PULSE + " not found");
}
}
mAppsPreference = (PreferenceGroup) root.findPreference(KEY_APPS_CATEGORY);
root.removePreference(mAppsPreference);
}
@Override
@@ -256,11 +158,6 @@ public class NotificationSettings extends SettingsPreferenceFragment implements
refreshNotificationListeners();
lookupRingtoneNames();
loadAppsList();
}
private void loadAppsList() {
AsyncTask.execute(mCollectAppsRunnable);
}
@Override
@@ -330,14 +227,9 @@ public class NotificationSettings extends SettingsPreferenceFragment implements
private void refreshNotificationListeners() {
if (mNotificationAccess != null) {
final PreferenceGroup securityCategory
= (PreferenceGroup) getPreferenceScreen().findPreference(KEY_SECURITY_CATEGORY);
final int total = NotificationAccessSettings.getListenersCount(mPM);
if (total == 0) {
if (securityCategory != null) {
securityCategory.removePreference(mNotificationAccess);
}
getPreferenceScreen().removePreference(mNotificationAccess);
} else {
final int n = getNumEnabledNotificationListeners();
if (n == 0) {
@@ -357,56 +249,4 @@ public class NotificationSettings extends SettingsPreferenceFragment implements
private void lookupRingtoneNames() {
new Thread(mRingtoneLookupRunnable).start();
}
// === Per-app notification settings row ==
private static class AppNotificationPreference extends Preference {
private Intent mIntent;
public AppNotificationPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
setLayoutResource(R.layout.notification_app);
}
public AppNotificationPreference(Context context, AttributeSet attrs, int defStyleAttr) {
this(context, attrs, defStyleAttr, 0);
}
public AppNotificationPreference(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public AppNotificationPreference(Context context) {
this(context, null);
}
public void setIntent(Intent intent) {
mIntent = intent;
}
@Override
protected void onBindView(View view) {
super.onBindView(view);
ImageView icon = (ImageView) view.findViewById(android.R.id.icon);
icon.setImageDrawable(getIcon());
TextView title = (TextView) view.findViewById(android.R.id.title);
title.setText(getTitle());
ImageView settingsButton = (ImageView) view.findViewById(android.R.id.button2);
settingsButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
getContext().startActivity(mIntent);
}
});
}
}
private static class AppNotificationInfo {
public Drawable icon;
public CharSequence label;
public String name;
public String pkg;
}
}

View File

@@ -14,16 +14,14 @@
* limitations under the License.
*/
package com.android.settings;
package com.android.settings.notification;
import android.app.Activity;
import android.app.ActivityManager;
import android.content.ComponentName;
import android.service.notification.INotificationListener;
import android.app.INotificationManager;
import android.app.Notification;
import android.service.notification.StatusBarNotification;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
@@ -37,6 +35,8 @@ import android.os.Handler;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
import android.service.notification.INotificationListener;
import android.service.notification.StatusBarNotification;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
@@ -48,6 +48,9 @@ import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import com.android.settings.R;
import com.android.settings.SettingsPreferenceFragment;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

View File

@@ -14,13 +14,13 @@
* limitations under the License.
*/
package com.android.settings;
package com.android.settings.notification;
import android.app.ActionBar;
import android.app.Activity;
import android.content.Context;
import android.database.ContentObserver;
import android.content.res.Resources;
import android.database.ContentObserver;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.net.Uri;
@@ -28,6 +28,7 @@ import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.provider.Settings.Global;
import android.provider.SearchIndexableResource;
import android.util.Log;
import android.util.TypedValue;
import android.view.Gravity;
@@ -45,6 +46,9 @@ import android.widget.ScrollView;
import android.widget.Switch;
import android.widget.TextView;
import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settings.R;
import com.android.settings.SettingsPreferenceFragment;
import com.android.settings.search.Indexable;
import com.android.settings.search.SearchIndexableRaw;

View File

@@ -17,27 +17,27 @@
package com.android.settings.search;
import android.provider.SearchIndexableResource;
import com.android.settings.DataUsageSummary;
import com.android.settings.DateTimeSettings;
import com.android.settings.DevelopmentSettings;
import com.android.settings.DeviceInfoSettings;
import com.android.settings.DisplaySettings;
import com.android.settings.HomeSettings;
import com.android.settings.NotificationSettings;
import com.android.settings.PrivacySettings;
import com.android.settings.R;
import com.android.settings.SecuritySettings;
import com.android.settings.SoundSettings;
import com.android.settings.WallpaperTypeSettings;
import com.android.settings.WirelessSettings;
import com.android.settings.ZenModeSettings;
import com.android.settings.accessibility.AccessibilitySettings;
import com.android.settings.bluetooth.BluetoothSettings;
import com.android.settings.deviceinfo.Memory;
import com.android.settings.fuelgauge.PowerUsageSummary;
import com.android.settings.inputmethod.InputMethodAndLanguageSettings;
import com.android.settings.location.LocationSettings;
import com.android.settings.net.DataUsageMeteredSettings;
import com.android.settings.notification.NotificationSettings;
import com.android.settings.notification.ZenModeSettings;
import com.android.settings.print.PrintSettingsFragment;
import com.android.settings.users.UserSettings;
import com.android.settings.wifi.WifiSettings;