| /* |
| * Copyright (C) 2018 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.settingslib.widget; |
| |
| import android.content.Context; |
| import android.content.res.Resources; |
| import android.text.TextUtils; |
| import android.util.Log; |
| import android.view.View; |
| import android.widget.Button; |
| import android.widget.ImageView; |
| import android.widget.TextView; |
| |
| import androidx.annotation.NonNull; |
| import androidx.annotation.Nullable; |
| import androidx.annotation.StringRes; |
| import androidx.annotation.VisibleForTesting; |
| |
| /** |
| * This class is used to initialize view which was inflated |
| * from {@link R.xml.app_entities_header.xml}. |
| * |
| * <p>How to use AppEntitiesHeaderController? |
| * |
| * <p>1. Add a {@link LayoutPreference} in layout XML file. |
| * <pre> |
| * <com.android.settingslib.widget.LayoutPreference |
| * android:key="app_entities_header" |
| * android:layout="@layout/app_entities_header"/> |
| * </pre> |
| * |
| * <p>2. Use AppEntitiesHeaderController to call below methods, then you can initialize |
| * view of <code>app_entities_header</code>. |
| * |
| * <pre> |
| * |
| * View headerView = ((LayoutPreference) screen.findPreference("app_entities_header")) |
| * .findViewById(R.id.app_entities_header); |
| * |
| * final AppEntityInfo appEntityInfo = new AppEntityInfo.Builder() |
| * .setIcon(icon) |
| * .setTitle(title) |
| * .setSummary(summary) |
| * .setOnClickListener(view -> doSomething()) |
| * .build(); |
| * |
| * AppEntitiesHeaderController.newInstance(context, headerView) |
| * .setHeaderTitleRes(R.string.xxxxx) |
| * .setHeaderDetailsRes(R.string.xxxxx) |
| * .setHeaderDetailsClickListener(onClickListener) |
| * .setAppEntity(0, appEntityInfo) |
| * .setAppEntity(1, appEntityInfo) |
| * .setAppEntity(2, appEntityInfo) |
| * .apply(); |
| * </pre> |
| */ |
| public class AppEntitiesHeaderController { |
| |
| private static final String TAG = "AppEntitiesHeaderCtl"; |
| |
| @VisibleForTesting |
| public static final int MAXIMUM_APPS = 3; |
| |
| private final Context mContext; |
| private final TextView mHeaderTitleView; |
| private final TextView mHeaderEmptyView; |
| private final Button mHeaderDetailsView; |
| |
| private final AppEntityInfo[] mAppEntityInfos; |
| private final View mAppViewsContainer; |
| private final View[] mAppEntityViews; |
| private final ImageView[] mAppIconViews; |
| private final TextView[] mAppTitleViews; |
| private final TextView[] mAppSummaryViews; |
| |
| private int mHeaderTitleRes; |
| private int mHeaderDetailsRes; |
| private int mHeaderEmptyRes; |
| private CharSequence mHeaderDetails; |
| private View.OnClickListener mDetailsOnClickListener; |
| |
| /** |
| * Creates a new instance of the controller. |
| * |
| * @param context the Context the view is running in |
| * @param appEntitiesHeaderView view was inflated from <code>app_entities_header</code> |
| */ |
| public static AppEntitiesHeaderController newInstance(@NonNull Context context, |
| @NonNull View appEntitiesHeaderView) { |
| return new AppEntitiesHeaderController(context, appEntitiesHeaderView); |
| } |
| |
| private AppEntitiesHeaderController(Context context, View appEntitiesHeaderView) { |
| mContext = context; |
| mHeaderTitleView = appEntitiesHeaderView.findViewById(R.id.header_title); |
| mHeaderDetailsView = appEntitiesHeaderView.findViewById(R.id.header_details); |
| mHeaderEmptyView = appEntitiesHeaderView.findViewById(R.id.empty_view); |
| mAppViewsContainer = appEntitiesHeaderView.findViewById(R.id.app_views_container); |
| |
| mAppEntityInfos = new AppEntityInfo[MAXIMUM_APPS]; |
| mAppIconViews = new ImageView[MAXIMUM_APPS]; |
| mAppTitleViews = new TextView[MAXIMUM_APPS]; |
| mAppSummaryViews = new TextView[MAXIMUM_APPS]; |
| |
| mAppEntityViews = new View[]{ |
| appEntitiesHeaderView.findViewById(R.id.app1_view), |
| appEntitiesHeaderView.findViewById(R.id.app2_view), |
| appEntitiesHeaderView.findViewById(R.id.app3_view) |
| }; |
| |
| // Initialize view in advance, so we won't take too much time to do it when controller is |
| // binding view. |
| for (int index = 0; index < MAXIMUM_APPS; index++) { |
| final View appView = mAppEntityViews[index]; |
| mAppIconViews[index] = (ImageView) appView.findViewById(R.id.app_icon); |
| mAppTitleViews[index] = (TextView) appView.findViewById(R.id.app_title); |
| mAppSummaryViews[index] = (TextView) appView.findViewById(R.id.app_summary); |
| } |
| } |
| |
| /** |
| * Set the text resource for app entities header title. |
| */ |
| public AppEntitiesHeaderController setHeaderTitleRes(@StringRes int titleRes) { |
| mHeaderTitleRes = titleRes; |
| return this; |
| } |
| |
| /** |
| * Set the text resource for app entities header details. |
| */ |
| public AppEntitiesHeaderController setHeaderDetailsRes(@StringRes int detailsRes) { |
| mHeaderDetailsRes = detailsRes; |
| return this; |
| } |
| |
| /** |
| * Set the text for app entities header details. |
| */ |
| public AppEntitiesHeaderController setHeaderDetails(CharSequence detailsText) { |
| mHeaderDetails = detailsText; |
| return this; |
| } |
| |
| /** |
| * Register a callback to be invoked when header details view is clicked. |
| */ |
| public AppEntitiesHeaderController setHeaderDetailsClickListener( |
| @Nullable View.OnClickListener clickListener) { |
| mDetailsOnClickListener = clickListener; |
| return this; |
| } |
| |
| /** |
| * Sets the string resource id for the empty text. |
| */ |
| public AppEntitiesHeaderController setHeaderEmptyRes(@StringRes int emptyRes) { |
| mHeaderEmptyRes = emptyRes; |
| return this; |
| } |
| |
| /** |
| * Set an app entity at a specified position view. |
| * |
| * @param index the index at which the specified view is to be inserted |
| * @param appEntityInfo the information of an app entity |
| * @return this {@code AppEntitiesHeaderController} object |
| */ |
| public AppEntitiesHeaderController setAppEntity(int index, |
| @NonNull AppEntityInfo appEntityInfo) { |
| mAppEntityInfos[index] = appEntityInfo; |
| return this; |
| } |
| |
| /** |
| * Remove an app entity at a specified position view. |
| * |
| * @param index the index at which the specified view is to be removed |
| * @return this {@code AppEntitiesHeaderController} object |
| */ |
| public AppEntitiesHeaderController removeAppEntity(int index) { |
| mAppEntityInfos[index] = null; |
| return this; |
| } |
| |
| /** |
| * Clear all app entities in app entities header. |
| * |
| * @return this {@code AppEntitiesHeaderController} object |
| */ |
| public AppEntitiesHeaderController clearAllAppEntities() { |
| for (int index = 0; index < MAXIMUM_APPS; index++) { |
| removeAppEntity(index); |
| } |
| return this; |
| } |
| |
| /** |
| * Done mutating app entities header, rebinds everything. |
| */ |
| public void apply() { |
| bindHeaderTitleView(); |
| |
| if (isAppEntityInfosEmpty()) { |
| setEmptyViewVisible(true); |
| return; |
| } |
| setEmptyViewVisible(false); |
| bindHeaderDetailsView(); |
| |
| // Rebind all apps view |
| for (int index = 0; index < MAXIMUM_APPS; index++) { |
| bindAppEntityView(index); |
| } |
| } |
| |
| private void bindHeaderTitleView() { |
| CharSequence titleText = ""; |
| try { |
| titleText = mContext.getText(mHeaderTitleRes); |
| } catch (Resources.NotFoundException e) { |
| Log.e(TAG, "Resource of header title can't not be found!", e); |
| } |
| mHeaderTitleView.setText(titleText); |
| mHeaderTitleView.setVisibility( |
| TextUtils.isEmpty(titleText) ? View.GONE : View.VISIBLE); |
| } |
| |
| private void bindHeaderDetailsView() { |
| CharSequence detailsText = mHeaderDetails; |
| if (TextUtils.isEmpty(detailsText)) { |
| try { |
| detailsText = mContext.getText(mHeaderDetailsRes); |
| } catch (Resources.NotFoundException e) { |
| Log.e(TAG, "Resource of header details can't not be found!", e); |
| } |
| } |
| mHeaderDetailsView.setText(detailsText); |
| mHeaderDetailsView.setVisibility( |
| TextUtils.isEmpty(detailsText) ? View.GONE : View.VISIBLE); |
| mHeaderDetailsView.setOnClickListener(mDetailsOnClickListener); |
| } |
| |
| private void bindAppEntityView(int index) { |
| final AppEntityInfo appEntityInfo = mAppEntityInfos[index]; |
| mAppEntityViews[index].setVisibility(appEntityInfo != null ? View.VISIBLE : View.GONE); |
| |
| if (appEntityInfo != null) { |
| mAppEntityViews[index].setOnClickListener(appEntityInfo.getClickListener()); |
| |
| mAppIconViews[index].setImageDrawable(appEntityInfo.getIcon()); |
| |
| final CharSequence title = appEntityInfo.getTitle(); |
| mAppTitleViews[index].setVisibility( |
| TextUtils.isEmpty(title) ? View.INVISIBLE : View.VISIBLE); |
| mAppTitleViews[index].setText(title); |
| |
| final CharSequence summary = appEntityInfo.getSummary(); |
| mAppSummaryViews[index].setVisibility( |
| TextUtils.isEmpty(summary) ? View.INVISIBLE : View.VISIBLE); |
| mAppSummaryViews[index].setText(summary); |
| } |
| } |
| |
| private void setEmptyViewVisible(boolean visible) { |
| if (mHeaderEmptyRes != 0) { |
| mHeaderEmptyView.setText(mHeaderEmptyRes); |
| } |
| mHeaderEmptyView.setVisibility(visible ? View.VISIBLE : View.GONE); |
| mHeaderDetailsView.setVisibility(visible ? View.GONE : View.VISIBLE); |
| mAppViewsContainer.setVisibility(visible ? View.GONE : View.VISIBLE); |
| } |
| |
| private boolean isAppEntityInfosEmpty() { |
| for (AppEntityInfo info : mAppEntityInfos) { |
| if (info != null) { |
| return false; |
| } |
| } |
| return true; |
| } |
| } |