/* * Copyright (C) 2016 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.settings.applications; import android.annotation.IdRes; import android.annotation.UserIdInt; import android.app.ActionBar; import android.app.Activity; import android.app.Fragment; import android.content.Context; import android.content.Intent; import android.content.pm.PackageInfo; import android.content.pm.ResolveInfo; import android.graphics.drawable.Drawable; import android.os.UserHandle; import android.support.annotation.IntDef; import android.support.annotation.VisibleForTesting; import android.text.TextUtils; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.widget.ImageButton; import android.widget.ImageView; import android.widget.TextView; import com.android.settings.AppHeader; import com.android.settings.R; import com.android.settings.Utils; import com.android.settings.overlay.FeatureFactory; import com.android.settingslib.applications.ApplicationsState; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; public class AppHeaderController { @IntDef({ActionType.ACTION_NONE, ActionType.ACTION_APP_INFO, ActionType.ACTION_APP_PREFERENCE, ActionType.ACTION_STORE_DEEP_LINK, ActionType.ACTION_NOTIF_PREFERENCE}) @Retention(RetentionPolicy.SOURCE) public @interface ActionType { int ACTION_NONE = 0; int ACTION_APP_INFO = 1; int ACTION_STORE_DEEP_LINK = 2; int ACTION_APP_PREFERENCE = 3; int ACTION_NOTIF_PREFERENCE = 4; } public static final String PREF_KEY_APP_HEADER = "pref_app_header"; private static final String TAG = "AppDetailFeature"; private final Context mContext; private final Fragment mFragment; private final int mMetricsCategory; private final View mAppHeader; private Drawable mIcon; private CharSequence mLabel; private CharSequence mSummary; private String mPackageName; private Intent mAppNotifPrefIntent; @UserIdInt private int mUid = UserHandle.USER_NULL; @ActionType private int mLeftAction; @ActionType private int mRightAction; private boolean mIsInstantApp; public AppHeaderController(Context context, Fragment fragment, View appHeader) { mContext = context; mFragment = fragment; mMetricsCategory = FeatureFactory.getFactory(context).getMetricsFeatureProvider() .getMetricsCategory(fragment); if (appHeader != null) { mAppHeader = appHeader; } else { mAppHeader = LayoutInflater.from(fragment.getContext()) .inflate(R.layout.app_details, null /* root */); } } public AppHeaderController setIcon(Drawable icon) { if (icon != null) { mIcon = icon.getConstantState().newDrawable(mContext.getResources()); } return this; } public AppHeaderController setIcon(ApplicationsState.AppEntry appEntry) { if (appEntry.icon != null) { mIcon = appEntry.icon.getConstantState().newDrawable(mContext.getResources()); } return this; } public AppHeaderController setLabel(CharSequence label) { mLabel = label; return this; } public AppHeaderController setLabel(ApplicationsState.AppEntry appEntry) { mLabel = appEntry.label; return this; } public AppHeaderController setSummary(CharSequence summary) { mSummary = summary; return this; } public AppHeaderController setSummary(PackageInfo packageInfo) { if (packageInfo != null) { mSummary = packageInfo.versionName; } return this; } public AppHeaderController setButtonActions(@ActionType int leftAction, @ActionType int rightAction) { mLeftAction = leftAction; mRightAction = rightAction; return this; } public AppHeaderController setPackageName(String packageName) { mPackageName = packageName; return this; } public AppHeaderController setUid(int uid) { mUid = uid; return this; } public AppHeaderController setAppNotifPrefIntent(Intent appNotifPrefIntent) { mAppNotifPrefIntent = appNotifPrefIntent; return this; } public AppHeaderController setIsInstantApp(boolean isInstantApp) { this.mIsInstantApp = isInstantApp; return this; } /** * Done mutating appheader, rebinds everything and return a new {@link LayoutPreference}. */ public LayoutPreference done(Activity activity, Context uiContext) { final LayoutPreference pref = new LayoutPreference(uiContext, done(activity)); // Makes sure it's the first preference onscreen. pref.setOrder(-1000); pref.setKey(PREF_KEY_APP_HEADER); return pref; } /** * Done mutating appheader, rebinds everything (optionally skip rebinding buttons). */ public View done(Activity activity, boolean rebindActions) { styleActionBar(activity); ImageView iconView = mAppHeader.findViewById(R.id.app_detail_icon); if (iconView != null) { iconView.setImageDrawable(mIcon); ImageView badgeView = mAppHeader.findViewById(R.id.app_icon_instant_apps_badge); if (badgeView != null) { badgeView.setVisibility(mIsInstantApp ? View.VISIBLE : View.GONE); } } setText(R.id.app_detail_title, mLabel); setText(R.id.app_detail_summary, mSummary); if (mIsInstantApp) { setText(R.id.install_type, mAppHeader.getResources().getString(R.string.install_type_instant)); } if (rebindActions) { bindAppHeaderButtons(); } return mAppHeader; } /** * Only binds app header with button actions. */ public AppHeaderController bindAppHeaderButtons() { ImageButton leftButton = mAppHeader.findViewById(R.id.left_button); ImageButton rightButton = mAppHeader.findViewById(R.id.right_button); bindButton(leftButton, mLeftAction); bindButton(rightButton, mRightAction); return this; } public AppHeaderController styleActionBar(Activity activity) { if (activity == null) { Log.w(TAG, "No activity, cannot style actionbar."); return this; } final ActionBar actionBar = activity.getActionBar(); if (actionBar == null) { Log.w(TAG, "No actionbar, cannot style actionbar."); return this; } final Drawable appHeaderBackground = mAppHeader.findViewById(R.id.app_snippet).getBackground(); actionBar.setBackgroundDrawable(appHeaderBackground); actionBar.setElevation(0); return this; } /** * Done mutating appheader, rebinds everything. */ @VisibleForTesting View done(Activity activity) { return done(activity, true /* rebindActions */); } private void bindButton(ImageButton button, @ActionType int action) { if (button == null) { return; } switch (action) { case ActionType.ACTION_APP_INFO: { if (mPackageName == null || mPackageName.equals(Utils.OS_PKG) || mUid == UserHandle.USER_NULL || !AppHeader.includeAppInfo(mFragment)) { button.setVisibility(View.GONE); } else { button.setContentDescription( mContext.getString(R.string.application_info_label)); button.setImageResource(com.android.settings.R.drawable.ic_info); button.setOnClickListener(v -> AppInfoBase.startAppInfoFragment( InstalledAppDetails.class, R.string.application_info_label, mPackageName, mUid, mFragment, 0 /* request */, mMetricsCategory)); button.setVisibility(View.VISIBLE); } return; } case ActionType.ACTION_STORE_DEEP_LINK: { final Intent intent = new Intent(Intent.ACTION_SHOW_APP_INFO) .setPackage(getInstallerPackageName(mContext, mPackageName)); final Intent result = resolveIntent(intent); if (result == null) { button.setVisibility(View.GONE); } else { result.putExtra(Intent.EXTRA_PACKAGE_NAME, mPackageName); button.setImageResource(R.drawable.ic_sim_sd); button.setOnClickListener(v -> mFragment.startActivity(intent)); button.setVisibility(View.VISIBLE); } return; } case ActionType.ACTION_NOTIF_PREFERENCE: { if (mAppNotifPrefIntent == null) { button.setVisibility(View.GONE); } else { button.setOnClickListener(v -> mFragment.startActivity(mAppNotifPrefIntent)); button.setVisibility(View.VISIBLE); } return; } case ActionType.ACTION_APP_PREFERENCE: { final Intent intent = resolveIntent( new Intent(Intent.ACTION_APPLICATION_PREFERENCES).setPackage(mPackageName)); if (intent == null) { button.setVisibility(View.GONE); return; } button.setOnClickListener(v -> mFragment.startActivity(intent)); button.setVisibility(View.VISIBLE); return; } case ActionType.ACTION_NONE: { button.setVisibility(View.GONE); return; } } } private String getInstallerPackageName(Context context, String packageName) { try { return context.getPackageManager().getInstallerPackageName(packageName); } catch (IllegalArgumentException e) { Log.e(TAG, "Exception while retrieving the package installer of " + packageName, e); return null; } } private Intent resolveIntent(Intent i) { ResolveInfo result = mContext.getPackageManager().resolveActivity(i, 0); if (result != null) { return new Intent(i.getAction()) .setClassName(result.activityInfo.packageName, result.activityInfo.name); } return null; } private void setText(@IdRes int id, CharSequence text) { TextView textView = mAppHeader.findViewById(id); if (textView != null) { textView.setText(text); textView.setVisibility(TextUtils.isEmpty(text) ? View.GONE : View.VISIBLE); } } }