blob: 6e95a0ed106add879c264f28bd39f313b356e341 [file] [log] [blame]
/*
* 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>
* &lt;com.android.settingslib.widget.LayoutPreference
* android:key="app_entities_header"
* android:layout="@layout/app_entities_header"/&gt;
* </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;
}
}