Home | History | Annotate | Download | only in applications
      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