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 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 100 public AppHeaderController setIcon(Drawable icon) { 101 if (icon != null) { 102 mIcon = icon.getConstantState().newDrawable(mContext.getResources()); 103 } 104 return this; 105 } 106 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 114 public AppHeaderController setLabel(CharSequence label) { 115 mLabel = label; 116 return this; 117 } 118 119 public AppHeaderController setLabel(ApplicationsState.AppEntry appEntry) { 120 mLabel = appEntry.label; 121 return this; 122 } 123 124 public AppHeaderController setSummary(CharSequence summary) { 125 mSummary = summary; 126 return this; 127 } 128 129 public AppHeaderController setSummary(PackageInfo packageInfo) { 130 if (packageInfo != null) { 131 mSummary = packageInfo.versionName; 132 } 133 return this; 134 } 135 136 public AppHeaderController setButtonActions(@ActionType int leftAction, 137 @ActionType int rightAction) { 138 mLeftAction = leftAction; 139 mRightAction = rightAction; 140 return this; 141 } 142 143 public AppHeaderController setPackageName(String packageName) { 144 mPackageName = packageName; 145 return this; 146 } 147 148 public AppHeaderController setUid(int uid) { 149 mUid = uid; 150 return this; 151 } 152 153 public AppHeaderController setAppNotifPrefIntent(Intent appNotifPrefIntent) { 154 mAppNotifPrefIntent = appNotifPrefIntent; 155 return this; 156 } 157 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 */ 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 */ 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 */ 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 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 230 View done(Activity activity) { 231 return done(activity, true /* rebindActions */); 232 } 233 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 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 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