1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.android.launcher3.settings;
17 
18 import static com.android.launcher3.settings.SettingsActivity.EXTRA_FRAGMENT_ARG_KEY;
19 import static com.android.launcher3.settings.SettingsActivity.EXTRA_SHOW_FRAGMENT_ARGS;
20 
21 import android.app.AlertDialog;
22 import android.app.Dialog;
23 import android.content.ComponentName;
24 import android.content.Context;
25 import android.content.DialogInterface;
26 import android.content.Intent;
27 import android.os.Bundle;
28 import android.provider.Settings;
29 import android.util.AttributeSet;
30 import android.view.View;
31 
32 import androidx.fragment.app.DialogFragment;
33 import androidx.preference.Preference;
34 import androidx.preference.PreferenceViewHolder;
35 
36 import com.android.launcher3.R;
37 import com.android.launcher3.notification.NotificationListener;
38 import com.android.launcher3.util.SecureSettingsObserver;
39 
40 /**
41  * A {@link Preference} for indicating notification dots status.
42  * Also has utility methods for updating UI based on dots status changes.
43  */
44 public class NotificationDotsPreference extends Preference
45         implements SecureSettingsObserver.OnChangeListener {
46 
47     private boolean mWidgetFrameVisible = false;
48 
49     /** Hidden field Settings.Secure.ENABLED_NOTIFICATION_LISTENERS */
50     private static final String NOTIFICATION_ENABLED_LISTENERS = "enabled_notification_listeners";
51 
NotificationDotsPreference( Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)52     public NotificationDotsPreference(
53             Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
54         super(context, attrs, defStyleAttr, defStyleRes);
55     }
56 
NotificationDotsPreference(Context context, AttributeSet attrs, int defStyleAttr)57     public NotificationDotsPreference(Context context, AttributeSet attrs, int defStyleAttr) {
58         super(context, attrs, defStyleAttr);
59     }
60 
NotificationDotsPreference(Context context, AttributeSet attrs)61     public NotificationDotsPreference(Context context, AttributeSet attrs) {
62         super(context, attrs);
63     }
64 
NotificationDotsPreference(Context context)65     public NotificationDotsPreference(Context context) {
66         super(context);
67     }
68 
setWidgetFrameVisible(boolean isVisible)69     private void setWidgetFrameVisible(boolean isVisible) {
70         if (mWidgetFrameVisible != isVisible) {
71             mWidgetFrameVisible = isVisible;
72             notifyChanged();
73         }
74     }
75 
76     @Override
onBindViewHolder(PreferenceViewHolder holder)77     public void onBindViewHolder(PreferenceViewHolder holder) {
78         super.onBindViewHolder(holder);
79 
80         View widgetFrame = holder.findViewById(android.R.id.widget_frame);
81         if (widgetFrame != null) {
82             widgetFrame.setVisibility(mWidgetFrameVisible ? View.VISIBLE : View.GONE);
83         }
84     }
85 
86     @Override
onSettingsChanged(boolean enabled)87     public void onSettingsChanged(boolean enabled) {
88         int summary = enabled
89                 ? R.string.notification_dots_desc_on
90                 : R.string.notification_dots_desc_off;
91 
92         boolean serviceEnabled = true;
93         if (enabled) {
94             // Check if the listener is enabled or not.
95             String enabledListeners = Settings.Secure.getString(
96                     getContext().getContentResolver(), NOTIFICATION_ENABLED_LISTENERS);
97             ComponentName myListener =
98                     new ComponentName(getContext(), NotificationListener.class);
99             serviceEnabled = enabledListeners != null &&
100                     (enabledListeners.contains(myListener.flattenToString()) ||
101                             enabledListeners.contains(myListener.flattenToShortString()));
102             if (!serviceEnabled) {
103                 summary = R.string.title_missing_notification_access;
104             }
105         }
106         setWidgetFrameVisible(!serviceEnabled);
107         setFragment(serviceEnabled ? null : NotificationAccessConfirmation.class.getName());
108         setSummary(summary);
109     }
110 
111     public static class NotificationAccessConfirmation
112             extends DialogFragment implements DialogInterface.OnClickListener {
113 
114         @Override
onCreateDialog(Bundle savedInstanceState)115         public Dialog onCreateDialog(Bundle savedInstanceState) {
116             final Context context = getActivity();
117             String msg = context.getString(R.string.msg_missing_notification_access,
118                     context.getString(R.string.derived_app_name));
119             return new AlertDialog.Builder(context)
120                     .setTitle(R.string.title_missing_notification_access)
121                     .setMessage(msg)
122                     .setNegativeButton(android.R.string.cancel, null)
123                     .setPositiveButton(R.string.title_change_settings, this)
124                     .create();
125         }
126 
127         @Override
onClick(DialogInterface dialogInterface, int i)128         public void onClick(DialogInterface dialogInterface, int i) {
129             ComponentName cn = new ComponentName(getActivity(), NotificationListener.class);
130             Bundle showFragmentArgs = new Bundle();
131             showFragmentArgs.putString(EXTRA_FRAGMENT_ARG_KEY, cn.flattenToString());
132 
133             Intent intent = new Intent(Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS)
134                     .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
135                     .putExtra(EXTRA_FRAGMENT_ARG_KEY, cn.flattenToString())
136                     .putExtra(EXTRA_SHOW_FRAGMENT_ARGS, showFragmentArgs);
137             getActivity().startActivity(intent);
138         }
139     }
140 }
141