OSDN Git Service

Zen automatic rule page ui changes
[android-x86/packages-apps-Settings.git] / src / com / android / settings / widget / EntityHeaderController.java
1 /*
2  * Copyright (C) 2016 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
17 package com.android.settings.widget;
18
19 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent
20         .ACTION_OPEN_APP_NOTIFICATION_SETTING;
21 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.ACTION_OPEN_APP_SETTING;
22
23 import android.annotation.IdRes;
24 import android.annotation.UserIdInt;
25 import android.app.ActionBar;
26 import android.app.Activity;
27 import android.app.Fragment;
28 import android.content.Context;
29 import android.content.Intent;
30 import android.content.pm.PackageInfo;
31 import android.content.pm.ResolveInfo;
32 import android.graphics.drawable.ColorDrawable;
33 import android.graphics.drawable.Drawable;
34 import android.os.Bundle;
35 import android.os.UserHandle;
36 import android.support.annotation.IntDef;
37 import android.support.annotation.VisibleForTesting;
38 import android.support.v7.widget.RecyclerView;
39 import android.text.TextUtils;
40 import android.util.FeatureFlagUtils;
41 import android.util.Log;
42 import android.view.LayoutInflater;
43 import android.view.View;
44 import android.widget.ImageButton;
45 import android.widget.ImageView;
46 import android.widget.TextView;
47
48 import com.android.settings.R;
49 import com.android.settings.Utils;
50 import com.android.settings.applications.AppInfoBase;
51 import com.android.settings.applications.InstalledAppDetails;
52 import com.android.settings.applications.LayoutPreference;
53 import com.android.settings.applications.appinfo.AppInfoDashboardFragment;
54 import com.android.settings.core.FeatureFlags;
55 import com.android.settings.overlay.FeatureFactory;
56 import com.android.settingslib.applications.ApplicationsState;
57 import com.android.settingslib.core.lifecycle.Lifecycle;
58
59 import java.lang.annotation.Retention;
60 import java.lang.annotation.RetentionPolicy;
61
62 public class EntityHeaderController {
63
64     @IntDef({ActionType.ACTION_NONE,
65             ActionType.ACTION_APP_PREFERENCE,
66             ActionType.ACTION_NOTIF_PREFERENCE,
67             ActionType.ACTION_DND_RULE_PREFERENCE,})
68     @Retention(RetentionPolicy.SOURCE)
69     public @interface ActionType {
70         int ACTION_NONE = 0;
71         int ACTION_APP_PREFERENCE = 1;
72         int ACTION_NOTIF_PREFERENCE = 2;
73         int ACTION_DND_RULE_PREFERENCE = 3;
74     }
75
76     public static final String PREF_KEY_APP_HEADER = "pref_app_header";
77
78     private static final String TAG = "AppDetailFeature";
79
80     private final Context mAppContext;
81     private final Activity mActivity;
82     private final Fragment mFragment;
83     private final int mMetricsCategory;
84     private final View mHeader;
85     private Lifecycle mLifecycle;
86     private RecyclerView mRecyclerView;
87     private Drawable mIcon;
88     private String mIconContentDescription;
89     private CharSequence mLabel;
90     private CharSequence mSummary;
91     private String mPackageName;
92     private Intent mAppNotifPrefIntent;
93     @UserIdInt
94     private int mUid = UserHandle.USER_NULL;
95     @ActionType
96     private int mAction1;
97     @ActionType
98     private int mAction2;
99
100     private boolean mHasAppInfoLink;
101
102     private boolean mIsInstantApp;
103
104     private View.OnClickListener mEditRuleNameOnClickListener;
105
106     /**
107      * Creates a new instance of the controller.
108      *
109      * @param fragment The fragment that header will be placed in.
110      * @param header   Optional: header view if it's already created.
111      */
112     public static EntityHeaderController newInstance(Activity activity, Fragment fragment,
113             View header) {
114         return new EntityHeaderController(activity, fragment, header);
115     }
116
117     private EntityHeaderController(Activity activity, Fragment fragment, View header) {
118         mActivity = activity;
119         mAppContext = activity.getApplicationContext();
120         mFragment = fragment;
121         mMetricsCategory = FeatureFactory.getFactory(mAppContext).getMetricsFeatureProvider()
122                 .getMetricsCategory(fragment);
123         if (header != null) {
124             mHeader = header;
125         } else {
126             mHeader = LayoutInflater.from(fragment.getContext())
127                     .inflate(R.layout.settings_entity_header, null /* root */);
128         }
129     }
130
131     public EntityHeaderController setRecyclerView(RecyclerView recyclerView, Lifecycle lifecycle) {
132         mRecyclerView = recyclerView;
133         mLifecycle = lifecycle;
134         return this;
135     }
136
137     /**
138      * Set the icon in the header. Callers should also consider calling setIconContentDescription
139      * to provide a description of this icon for accessibility purposes.
140      */
141     public EntityHeaderController setIcon(Drawable icon) {
142         if (icon != null) {
143             mIcon = icon.getConstantState().newDrawable(mAppContext.getResources());
144         }
145         return this;
146     }
147
148     /**
149      * Convenience method to set the header icon from an ApplicationsState.AppEntry. Callers should
150      * also consider calling setIconContentDescription to provide a description of this icon for
151      * accessibility purposes.
152      */
153     public EntityHeaderController setIcon(ApplicationsState.AppEntry appEntry) {
154         if (appEntry.icon != null) {
155             mIcon = appEntry.icon.getConstantState().newDrawable(mAppContext.getResources());
156         }
157         return this;
158     }
159
160     public EntityHeaderController setIconContentDescription(String contentDescription) {
161         mIconContentDescription = contentDescription;
162         return this;
163     }
164
165     public EntityHeaderController setLabel(CharSequence label) {
166         mLabel = label;
167         return this;
168     }
169
170     public EntityHeaderController setLabel(ApplicationsState.AppEntry appEntry) {
171         mLabel = appEntry.label;
172         return this;
173     }
174
175     public EntityHeaderController setSummary(CharSequence summary) {
176         mSummary = summary;
177         return this;
178     }
179
180     public EntityHeaderController setSummary(PackageInfo packageInfo) {
181         if (packageInfo != null) {
182             mSummary = packageInfo.versionName;
183         }
184         return this;
185     }
186
187     public EntityHeaderController setHasAppInfoLink(boolean hasAppInfoLink) {
188         mHasAppInfoLink = hasAppInfoLink;
189         return this;
190     }
191
192     public EntityHeaderController setButtonActions(@ActionType int action1,
193             @ActionType int action2) {
194         mAction1 = action1;
195         mAction2 = action2;
196         return this;
197     }
198
199     public EntityHeaderController setPackageName(String packageName) {
200         mPackageName = packageName;
201         return this;
202     }
203
204     public EntityHeaderController setUid(int uid) {
205         mUid = uid;
206         return this;
207     }
208
209     public EntityHeaderController setAppNotifPrefIntent(Intent appNotifPrefIntent) {
210         mAppNotifPrefIntent = appNotifPrefIntent;
211         return this;
212     }
213
214     public EntityHeaderController setIsInstantApp(boolean isInstantApp) {
215         this.mIsInstantApp = isInstantApp;
216         return this;
217     }
218
219     public EntityHeaderController setEditZenRuleNameListener(View.OnClickListener listener) {
220         this.mEditRuleNameOnClickListener = listener;
221         return this;
222     }
223
224     /**
225      * Done mutating entity header, rebinds everything and return a new {@link LayoutPreference}.
226      */
227     public LayoutPreference done(Activity activity, Context uiContext) {
228         final LayoutPreference pref = new LayoutPreference(uiContext, done(activity));
229         // Makes sure it's the first preference onscreen.
230         pref.setOrder(-1000);
231         pref.setSelectable(false);
232         pref.setKey(PREF_KEY_APP_HEADER);
233         return pref;
234     }
235
236     /**
237      * Done mutating entity header, rebinds everything (optionally skip rebinding buttons).
238      */
239     public View done(Activity activity, boolean rebindActions) {
240         styleActionBar(activity);
241         ImageView iconView = mHeader.findViewById(R.id.entity_header_icon);
242         if (iconView != null) {
243             iconView.setImageDrawable(mIcon);
244             iconView.setContentDescription(mIconContentDescription);
245         }
246         setText(R.id.entity_header_title, mLabel);
247         setText(R.id.entity_header_summary, mSummary);
248         if (mIsInstantApp) {
249             setText(R.id.install_type,
250                     mHeader.getResources().getString(R.string.install_type_instant));
251         }
252
253         if (rebindActions) {
254             bindHeaderButtons();
255         }
256
257         return mHeader;
258     }
259
260     /**
261      * Only binds entity header with button actions.
262      */
263     public EntityHeaderController bindHeaderButtons() {
264         final View entityHeaderContent = mHeader.findViewById(R.id.entity_header_content);
265         final ImageButton button1 = mHeader.findViewById(android.R.id.button1);
266         final ImageButton button2 = mHeader.findViewById(android.R.id.button2);
267         bindAppInfoLink(entityHeaderContent);
268         bindButton(button1, mAction1);
269         bindButton(button2, mAction2);
270         return this;
271     }
272
273     private void bindAppInfoLink(View entityHeaderContent) {
274         if (!mHasAppInfoLink) {
275             // Caller didn't ask for app link, skip.
276             return;
277         }
278         if (entityHeaderContent == null
279                 || mPackageName == null
280                 || mPackageName.equals(Utils.OS_PKG)
281                 || mUid == UserHandle.USER_NULL) {
282             Log.w(TAG, "Missing ingredients to build app info link, skip");
283             return;
284         }
285         entityHeaderContent.setOnClickListener(new View.OnClickListener() {
286             @Override
287             public void onClick(View v) {
288                 if (FeatureFlagUtils.isEnabled(mAppContext, FeatureFlags.APP_INFO_V2)) {
289                     AppInfoBase.startAppInfoFragment(
290                             AppInfoDashboardFragment.class, R.string.application_info_label,
291                             mPackageName, mUid, mFragment, 0 /* request */,
292                             mMetricsCategory);
293                 } else {
294                     AppInfoBase.startAppInfoFragment(
295                             InstalledAppDetails.class, R.string.application_info_label,
296                             mPackageName, mUid, mFragment, 0 /* request */,
297                             mMetricsCategory);
298                 }
299             }
300         });
301         return;
302     }
303
304     /**
305      * Styles the action bar (elevation, scrolling behaviors, color, etc).
306      * <p/>
307      * This method must be called after {@link Fragment#onCreate(Bundle)}.
308      */
309     public EntityHeaderController styleActionBar(Activity activity) {
310         if (activity == null) {
311             Log.w(TAG, "No activity, cannot style actionbar.");
312             return this;
313         }
314         final ActionBar actionBar = activity.getActionBar();
315         if (actionBar == null) {
316             Log.w(TAG, "No actionbar, cannot style actionbar.");
317             return this;
318         }
319         actionBar.setBackgroundDrawable(
320                 new ColorDrawable(Utils.getColorAttr(activity, android.R.attr.colorSecondary)));
321         actionBar.setElevation(0);
322         if (mRecyclerView != null && mLifecycle != null) {
323             ActionBarShadowController.attachToRecyclerView(mActivity, mLifecycle, mRecyclerView);
324         }
325
326         return this;
327     }
328
329     /**
330      * Done mutating entity header, rebinds everything.
331      */
332     @VisibleForTesting
333     View done(Activity activity) {
334         return done(activity, true /* rebindActions */);
335     }
336
337     private void bindButton(ImageButton button, @ActionType int action) {
338         if (button == null) {
339             return;
340         }
341         switch (action) {
342             case ActionType.ACTION_DND_RULE_PREFERENCE: {
343                 if (mEditRuleNameOnClickListener == null) {
344                     button.setVisibility(View.GONE);
345                 } else {
346                     button.setImageResource(R.drawable.ic_mode_edit);
347                     button.setVisibility(View.VISIBLE);
348                     button.setOnClickListener(mEditRuleNameOnClickListener);
349                 }
350                 return;
351             }
352             case ActionType.ACTION_NOTIF_PREFERENCE: {
353                 if (mAppNotifPrefIntent == null) {
354                     button.setVisibility(View.GONE);
355                 } else {
356                     button.setOnClickListener(new View.OnClickListener() {
357                         @Override
358                         public void onClick(View v) {
359                             FeatureFactory.getFactory(mAppContext).getMetricsFeatureProvider()
360                                     .actionWithSource(mAppContext, mMetricsCategory,
361                                             ACTION_OPEN_APP_NOTIFICATION_SETTING);
362                             mFragment.startActivity(mAppNotifPrefIntent);
363                         }
364                     });
365                     button.setVisibility(View.VISIBLE);
366                 }
367                 return;
368             }
369             case ActionType.ACTION_APP_PREFERENCE: {
370                 final Intent intent = resolveIntent(
371                         new Intent(Intent.ACTION_APPLICATION_PREFERENCES).setPackage(mPackageName));
372                 if (intent == null) {
373                     button.setImageDrawable(null);
374                     button.setVisibility(View.GONE);
375                     return;
376                 }
377                 button.setOnClickListener(new View.OnClickListener() {
378                     @Override
379                     public void onClick(View v) {
380                         FeatureFactory.getFactory(mAppContext).getMetricsFeatureProvider()
381                                 .actionWithSource(mAppContext, mMetricsCategory,
382                                         ACTION_OPEN_APP_SETTING);
383                         mFragment.startActivity(intent);
384                     }
385                 });
386                 button.setImageResource(R.drawable.ic_settings_24dp);
387                 button.setVisibility(View.VISIBLE);
388                 return;
389             }
390             case ActionType.ACTION_NONE: {
391                 button.setVisibility(View.GONE);
392                 return;
393             }
394         }
395     }
396
397     private Intent resolveIntent(Intent i) {
398         ResolveInfo result = mAppContext.getPackageManager().resolveActivity(i, 0);
399         if (result != null) {
400             return new Intent(i.getAction())
401                     .setClassName(result.activityInfo.packageName, result.activityInfo.name);
402         }
403         return null;
404     }
405
406     private void setText(@IdRes int id, CharSequence text) {
407         TextView textView = mHeader.findViewById(id);
408         if (textView != null) {
409             textView.setText(text);
410             textView.setVisibility(TextUtils.isEmpty(text) ? View.GONE : View.VISIBLE);
411         }
412     }
413 }