• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.applications;
18 
19 import android.annotation.IdRes;
20 import android.annotation.UserIdInt;
21 import android.app.ActionBar;
22 import android.app.Activity;
23 import android.app.Fragment;
24 import android.content.Context;
25 import android.content.Intent;
26 import android.content.pm.PackageInfo;
27 import android.content.pm.ResolveInfo;
28 import android.graphics.drawable.ColorDrawable;
29 import android.graphics.drawable.Drawable;
30 import android.os.UserHandle;
31 import android.support.annotation.IntDef;
32 import android.support.annotation.VisibleForTesting;
33 import android.text.TextUtils;
34 import android.util.Log;
35 import android.view.LayoutInflater;
36 import android.view.View;
37 import android.widget.ImageButton;
38 import android.widget.ImageView;
39 import android.widget.TextView;
40 
41 import com.android.settings.AppHeader;
42 import com.android.settings.R;
43 import com.android.settings.Utils;
44 import com.android.settings.overlay.FeatureFactory;
45 import com.android.settingslib.applications.ApplicationsState;
46 
47 import java.lang.annotation.Retention;
48 import java.lang.annotation.RetentionPolicy;
49 
50 public class AppHeaderController {
51 
52     @IntDef({ActionType.ACTION_NONE,
53             ActionType.ACTION_APP_INFO,
54             ActionType.ACTION_APP_PREFERENCE,
55             ActionType.ACTION_NOTIF_PREFERENCE})
56     @Retention(RetentionPolicy.SOURCE)
57     public @interface ActionType {
58         int ACTION_NONE = 0;
59         int ACTION_APP_INFO = 1;
60         int ACTION_APP_PREFERENCE = 2;
61         int ACTION_NOTIF_PREFERENCE = 3;
62     }
63 
64     public static final String PREF_KEY_APP_HEADER = "pref_app_header";
65 
66     private static final String TAG = "AppDetailFeature";
67 
68     private final Context mContext;
69     private final Fragment mFragment;
70     private final int mMetricsCategory;
71     private final View mAppHeader;
72 
73     private Drawable mIcon;
74     private CharSequence mLabel;
75     private CharSequence mSummary;
76     private String mPackageName;
77     private Intent mAppNotifPrefIntent;
78     @UserIdInt
79     private int mUid = UserHandle.USER_NULL;
80     @ActionType
81     private int mLeftAction;
82     @ActionType
83     private int mRightAction;
84 
85     private boolean mIsInstantApp;
86 
AppHeaderController(Context context, Fragment fragment, View appHeader)87     public AppHeaderController(Context context, Fragment fragment, View appHeader) {
88         mContext = context;
89         mFragment = fragment;
90         mMetricsCategory = FeatureFactory.getFactory(context).getMetricsFeatureProvider()
91                 .getMetricsCategory(fragment);
92         if (appHeader != null) {
93             mAppHeader = appHeader;
94         } else {
95             mAppHeader = LayoutInflater.from(fragment.getContext())
96                     .inflate(R.layout.app_details, null /* root */);
97         }
98     }
99 
setIcon(Drawable icon)100     public AppHeaderController setIcon(Drawable icon) {
101         if (icon != null) {
102             mIcon = icon.getConstantState().newDrawable(mContext.getResources());
103         }
104         return this;
105     }
106 
setIcon(ApplicationsState.AppEntry appEntry)107     public AppHeaderController setIcon(ApplicationsState.AppEntry appEntry) {
108         if (appEntry.icon != null) {
109             mIcon = appEntry.icon.getConstantState().newDrawable(mContext.getResources());
110         }
111         return this;
112     }
113 
setLabel(CharSequence label)114     public AppHeaderController setLabel(CharSequence label) {
115         mLabel = label;
116         return this;
117     }
118 
setLabel(ApplicationsState.AppEntry appEntry)119     public AppHeaderController setLabel(ApplicationsState.AppEntry appEntry) {
120         mLabel = appEntry.label;
121         return this;
122     }
123 
setSummary(CharSequence summary)124     public AppHeaderController setSummary(CharSequence summary) {
125         mSummary = summary;
126         return this;
127     }
128 
setSummary(PackageInfo packageInfo)129     public AppHeaderController setSummary(PackageInfo packageInfo) {
130         if (packageInfo != null) {
131             mSummary = packageInfo.versionName;
132         }
133         return this;
134     }
135 
setButtonActions(@ctionType int leftAction, @ActionType int rightAction)136     public AppHeaderController setButtonActions(@ActionType int leftAction,
137             @ActionType int rightAction) {
138         mLeftAction = leftAction;
139         mRightAction = rightAction;
140         return this;
141     }
142 
setPackageName(String packageName)143     public AppHeaderController setPackageName(String packageName) {
144         mPackageName = packageName;
145         return this;
146     }
147 
setUid(int uid)148     public AppHeaderController setUid(int uid) {
149         mUid = uid;
150         return this;
151     }
152 
setAppNotifPrefIntent(Intent appNotifPrefIntent)153     public AppHeaderController setAppNotifPrefIntent(Intent appNotifPrefIntent) {
154         mAppNotifPrefIntent = appNotifPrefIntent;
155         return this;
156     }
157 
setIsInstantApp(boolean isInstantApp)158     public AppHeaderController setIsInstantApp(boolean isInstantApp) {
159         this.mIsInstantApp = isInstantApp;
160         return this;
161     }
162 
163     /**
164      * Done mutating appheader, rebinds everything and return a new {@link LayoutPreference}.
165      */
done(Activity activity, Context uiContext)166     public LayoutPreference done(Activity activity, Context uiContext) {
167         final LayoutPreference pref = new LayoutPreference(uiContext, done(activity));
168         // Makes sure it's the first preference onscreen.
169         pref.setOrder(-1000);
170         pref.setKey(PREF_KEY_APP_HEADER);
171         return pref;
172     }
173 
174     /**
175      * Done mutating appheader, rebinds everything (optionally skip rebinding buttons).
176      */
done(Activity activity, boolean rebindActions)177     public View done(Activity activity, boolean rebindActions) {
178         styleActionBar(activity);
179         ImageView iconView = mAppHeader.findViewById(R.id.app_detail_icon);
180         if (iconView != null) {
181             iconView.setImageDrawable(mIcon);
182         }
183         setText(R.id.app_detail_title, mLabel);
184         setText(R.id.app_detail_summary, mSummary);
185         if (mIsInstantApp) {
186             setText(R.id.install_type,
187                     mAppHeader.getResources().getString(R.string.install_type_instant));
188         }
189 
190         if (rebindActions) {
191             bindAppHeaderButtons();
192         }
193 
194         return mAppHeader;
195     }
196 
197     /**
198      * Only binds app header with button actions.
199      */
bindAppHeaderButtons()200     public AppHeaderController bindAppHeaderButtons() {
201         ImageButton leftButton = mAppHeader.findViewById(R.id.left_button);
202         ImageButton rightButton = mAppHeader.findViewById(R.id.right_button);
203 
204         bindButton(leftButton, mLeftAction);
205         bindButton(rightButton, mRightAction);
206         return this;
207     }
208 
styleActionBar(Activity activity)209     public AppHeaderController styleActionBar(Activity activity) {
210         if (activity == null) {
211             Log.w(TAG, "No activity, cannot style actionbar.");
212             return this;
213         }
214         final ActionBar actionBar = activity.getActionBar();
215         if (actionBar == null) {
216             Log.w(TAG, "No actionbar, cannot style actionbar.");
217             return this;
218         }
219         actionBar.setBackgroundDrawable(
220                 new ColorDrawable(Utils.getColorAttr(activity, android.R.attr.colorSecondary)));
221         actionBar.setElevation(0);
222 
223         return this;
224     }
225 
226     /**
227      * Done mutating appheader, rebinds everything.
228      */
229     @VisibleForTesting
done(Activity activity)230     View done(Activity activity) {
231         return done(activity, true /* rebindActions */);
232     }
233 
bindButton(ImageButton button, @ActionType int action)234     private void bindButton(ImageButton button, @ActionType int action) {
235         if (button == null) {
236             return;
237         }
238         switch (action) {
239             case ActionType.ACTION_APP_INFO: {
240                 if (mPackageName == null || mPackageName.equals(Utils.OS_PKG)
241                         || mUid == UserHandle.USER_NULL
242                         || !AppHeader.includeAppInfo(mFragment)) {
243                     button.setVisibility(View.GONE);
244                 } else {
245                     button.setContentDescription(
246                             mContext.getString(R.string.application_info_label));
247                     button.setImageResource(com.android.settings.R.drawable.ic_info);
248                     button.setOnClickListener(v -> AppInfoBase.startAppInfoFragment(
249                             InstalledAppDetails.class, R.string.application_info_label,
250                             mPackageName, mUid, mFragment, 0 /* request */, mMetricsCategory));
251                     button.setVisibility(View.VISIBLE);
252                 }
253                 return;
254             }
255             case ActionType.ACTION_NOTIF_PREFERENCE: {
256                 if (mAppNotifPrefIntent == null) {
257                     button.setVisibility(View.GONE);
258                 } else {
259                     button.setOnClickListener(v -> mFragment.startActivity(mAppNotifPrefIntent));
260                     button.setVisibility(View.VISIBLE);
261                 }
262                 return;
263             }
264             case ActionType.ACTION_APP_PREFERENCE: {
265                 final Intent intent = resolveIntent(
266                         new Intent(Intent.ACTION_APPLICATION_PREFERENCES).setPackage(mPackageName));
267                 if (intent == null) {
268                     button.setVisibility(View.GONE);
269                     return;
270                 }
271                 button.setOnClickListener(v -> mFragment.startActivity(intent));
272                 button.setVisibility(View.VISIBLE);
273                 return;
274             }
275             case ActionType.ACTION_NONE: {
276                 button.setVisibility(View.GONE);
277                 return;
278             }
279         }
280     }
281 
resolveIntent(Intent i)282     private Intent resolveIntent(Intent i) {
283         ResolveInfo result = mContext.getPackageManager().resolveActivity(i, 0);
284         if (result != null) {
285             return new Intent(i.getAction())
286                     .setClassName(result.activityInfo.packageName, result.activityInfo.name);
287         }
288         return null;
289     }
290 
setText(@dRes int id, CharSequence text)291     private void setText(@IdRes int id, CharSequence text) {
292         TextView textView = mAppHeader.findViewById(id);
293         if (textView != null) {
294             textView.setText(text);
295             textView.setVisibility(TextUtils.isEmpty(text) ? View.GONE : View.VISIBLE);
296         }
297     }
298 }
299