Having consistent import order will reduce chance of merge conflict between internal and external master Test: rebuild Change-Id: I0b1a170967ddcce7f388603fd521f6ed1eeba30b
293 lines
11 KiB
Java
293 lines
11 KiB
Java
/*
|
|
* Copyright (C) 2014 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.dashboard;
|
|
|
|
import android.app.Activity;
|
|
import android.content.Context;
|
|
import android.os.Bundle;
|
|
import android.os.Handler;
|
|
import android.service.settings.suggestions.Suggestion;
|
|
import android.util.Log;
|
|
import android.view.LayoutInflater;
|
|
import android.view.View;
|
|
import android.view.ViewGroup;
|
|
|
|
import androidx.annotation.VisibleForTesting;
|
|
import androidx.annotation.WorkerThread;
|
|
import androidx.loader.app.LoaderManager;
|
|
import androidx.recyclerview.widget.LinearLayoutManager;
|
|
|
|
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
|
|
import com.android.settings.R;
|
|
import com.android.settings.core.InstrumentedFragment;
|
|
import com.android.settings.core.SettingsBaseActivity;
|
|
import com.android.settings.core.SettingsBaseActivity.CategoryListener;
|
|
import com.android.settings.dashboard.suggestions.SuggestionFeatureProvider;
|
|
import com.android.settings.homepage.conditional.ConditionListener;
|
|
import com.android.settings.homepage.conditional.ConditionManager;
|
|
import com.android.settings.homepage.conditional.FocusRecyclerView;
|
|
import com.android.settings.homepage.conditional.FocusRecyclerView.FocusListener;
|
|
import com.android.settings.overlay.FeatureFactory;
|
|
import com.android.settings.widget.ActionBarShadowController;
|
|
import com.android.settingslib.drawer.CategoryKey;
|
|
import com.android.settingslib.drawer.DashboardCategory;
|
|
import com.android.settingslib.suggestions.SuggestionControllerMixinCompat;
|
|
import com.android.settingslib.utils.ThreadUtils;
|
|
|
|
import java.util.List;
|
|
|
|
/**
|
|
* Deprecated in favor of {@link com.android.settings.homepage.TopLevelSettings}
|
|
*
|
|
* @deprecated
|
|
*/
|
|
@Deprecated
|
|
public class DashboardSummary extends InstrumentedFragment
|
|
implements CategoryListener, ConditionListener,
|
|
FocusListener, SuggestionControllerMixinCompat.SuggestionControllerHost {
|
|
public static final boolean DEBUG = false;
|
|
private static final boolean DEBUG_TIMING = false;
|
|
private static final int MAX_WAIT_MILLIS = 3000;
|
|
private static final String TAG = "DashboardSummary";
|
|
|
|
private static final String STATE_SCROLL_POSITION = "scroll_position";
|
|
private static final String STATE_CATEGORIES_CHANGE_CALLED = "categories_change_called";
|
|
|
|
private final Handler mHandler = new Handler();
|
|
|
|
private FocusRecyclerView mDashboard;
|
|
private DashboardAdapter mAdapter;
|
|
private SummaryLoader mSummaryLoader;
|
|
private ConditionManager mConditionManager;
|
|
private LinearLayoutManager mLayoutManager;
|
|
private SuggestionControllerMixinCompat mSuggestionControllerMixin;
|
|
private DashboardFeatureProvider mDashboardFeatureProvider;
|
|
@VisibleForTesting
|
|
boolean mIsOnCategoriesChangedCalled;
|
|
private boolean mOnConditionsChangedCalled;
|
|
|
|
private DashboardCategory mStagingCategory;
|
|
private List<Suggestion> mStagingSuggestions;
|
|
|
|
@Override
|
|
public int getMetricsCategory() {
|
|
return MetricsEvent.DASHBOARD_SUMMARY;
|
|
}
|
|
|
|
@Override
|
|
public void onAttach(Context context) {
|
|
super.onAttach(context);
|
|
Log.d(TAG, "Creating SuggestionControllerMixinCompat");
|
|
final SuggestionFeatureProvider suggestionFeatureProvider = FeatureFactory
|
|
.getFactory(context)
|
|
.getSuggestionFeatureProvider(context);
|
|
if (suggestionFeatureProvider.isSuggestionEnabled(context)) {
|
|
mSuggestionControllerMixin = new SuggestionControllerMixinCompat(
|
|
context, this /* host */, getSettingsLifecycle(),
|
|
suggestionFeatureProvider.getSuggestionServiceComponent());
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public LoaderManager getLoaderManager() {
|
|
if (!isAdded()) {
|
|
return null;
|
|
}
|
|
return super.getLoaderManager();
|
|
}
|
|
|
|
@Override
|
|
public void onCreate(Bundle savedInstanceState) {
|
|
long startTime = System.currentTimeMillis();
|
|
super.onCreate(savedInstanceState);
|
|
Log.d(TAG, "Starting DashboardSummary");
|
|
final Activity activity = getActivity();
|
|
mDashboardFeatureProvider = FeatureFactory.getFactory(activity)
|
|
.getDashboardFeatureProvider(activity);
|
|
|
|
mSummaryLoader = new SummaryLoader(activity, CategoryKey.CATEGORY_HOMEPAGE);
|
|
|
|
mConditionManager =
|
|
new ConditionManager(
|
|
activity, this /* listener */);
|
|
if (savedInstanceState != null) {
|
|
mIsOnCategoriesChangedCalled =
|
|
savedInstanceState.getBoolean(STATE_CATEGORIES_CHANGE_CALLED);
|
|
}
|
|
if (DEBUG_TIMING) {
|
|
Log.d(TAG, "onCreate took " + (System.currentTimeMillis() - startTime) + " ms");
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onDestroy() {
|
|
mSummaryLoader.release();
|
|
super.onDestroy();
|
|
}
|
|
|
|
@Override
|
|
public void onResume() {
|
|
long startTime = System.currentTimeMillis();
|
|
super.onResume();
|
|
|
|
((SettingsBaseActivity) getActivity()).addCategoryListener(this);
|
|
mSummaryLoader.setListening(true);
|
|
mConditionManager.startMonitoringStateChange();
|
|
if (DEBUG_TIMING) {
|
|
Log.d(TAG, "onResume took " + (System.currentTimeMillis() - startTime) + " ms");
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onPause() {
|
|
super.onPause();
|
|
|
|
((SettingsBaseActivity) getActivity()).remCategoryListener(this);
|
|
mSummaryLoader.setListening(false);
|
|
mConditionManager.stopMonitoringStateChange();
|
|
}
|
|
|
|
@Override
|
|
public void onWindowFocusChanged(boolean hasWindowFocus) {
|
|
long startTime = System.currentTimeMillis();
|
|
if (hasWindowFocus) {
|
|
mConditionManager.startMonitoringStateChange();
|
|
} else {
|
|
mConditionManager.stopMonitoringStateChange();
|
|
}
|
|
if (DEBUG_TIMING) {
|
|
Log.d(TAG, "onWindowFocusChanged took "
|
|
+ (System.currentTimeMillis() - startTime) + " ms");
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onSaveInstanceState(Bundle outState) {
|
|
super.onSaveInstanceState(outState);
|
|
if (mLayoutManager == null) {
|
|
return;
|
|
}
|
|
outState.putBoolean(STATE_CATEGORIES_CHANGE_CALLED, mIsOnCategoriesChangedCalled);
|
|
outState.putInt(STATE_SCROLL_POSITION, mLayoutManager.findFirstVisibleItemPosition());
|
|
}
|
|
|
|
@Override
|
|
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) {
|
|
long startTime = System.currentTimeMillis();
|
|
final View root = inflater.inflate(R.layout.dashboard, container, false);
|
|
mDashboard = root.findViewById(R.id.dashboard_container);
|
|
mLayoutManager = new LinearLayoutManager(getContext());
|
|
mLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
|
|
if (bundle != null) {
|
|
int scrollPosition = bundle.getInt(STATE_SCROLL_POSITION);
|
|
mLayoutManager.scrollToPosition(scrollPosition);
|
|
}
|
|
mDashboard.setLayoutManager(mLayoutManager);
|
|
mDashboard.setHasFixedSize(true);
|
|
mDashboard.setListener(this);
|
|
mDashboard.setItemAnimator(new DashboardItemAnimator());
|
|
mAdapter = new DashboardAdapter(getContext(), bundle,
|
|
mConditionManager,
|
|
mSuggestionControllerMixin,
|
|
getSettingsLifecycle());
|
|
mDashboard.setAdapter(mAdapter);
|
|
mSummaryLoader.setSummaryConsumer(mAdapter);
|
|
ActionBarShadowController.attachToRecyclerView(
|
|
getActivity().findViewById(R.id.search_bar_container), getSettingsLifecycle(),
|
|
mDashboard);
|
|
rebuildUI();
|
|
if (DEBUG_TIMING) {
|
|
Log.d(TAG, "onCreateView took "
|
|
+ (System.currentTimeMillis() - startTime) + " ms");
|
|
}
|
|
return root;
|
|
}
|
|
|
|
@VisibleForTesting
|
|
void rebuildUI() {
|
|
ThreadUtils.postOnBackgroundThread(() -> updateCategory());
|
|
}
|
|
|
|
@Override
|
|
public void onCategoriesChanged() {
|
|
// Bypass rebuildUI() on the first call of onCategoriesChanged, since rebuildUI() happens
|
|
// in onViewCreated as well when app starts. But, on the subsequent calls we need to
|
|
// rebuildUI() because there might be some changes to suggestions and categories.
|
|
if (mIsOnCategoriesChangedCalled) {
|
|
rebuildUI();
|
|
}
|
|
mIsOnCategoriesChangedCalled = true;
|
|
}
|
|
|
|
@Override
|
|
public void onConditionsChanged() {
|
|
Log.d(TAG, "onConditionsChanged");
|
|
// Bypass refreshing the conditions on the first call of onConditionsChanged.
|
|
// onConditionsChanged is called immediately everytime we start listening to the conditions
|
|
// change when we gain window focus. Since the conditions are passed to the adapter's
|
|
// constructor when we create the view, the first handling is not necessary.
|
|
// But, on the subsequent calls we need to handle it because there might be real changes to
|
|
// conditions.
|
|
if (mOnConditionsChangedCalled) {
|
|
final boolean scrollToTop =
|
|
mLayoutManager.findFirstCompletelyVisibleItemPosition() <= 1;
|
|
mAdapter.setConditions(mConditionManager.getDisplayableCards());
|
|
|
|
if (scrollToTop) {
|
|
mDashboard.scrollToPosition(0);
|
|
}
|
|
} else {
|
|
mOnConditionsChangedCalled = true;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onSuggestionReady(List<Suggestion> suggestions) {
|
|
mStagingSuggestions = suggestions;
|
|
mAdapter.setSuggestions(suggestions);
|
|
if (mStagingCategory != null) {
|
|
Log.d(TAG, "Category has loaded, setting category from suggestionReady");
|
|
mHandler.removeCallbacksAndMessages(null);
|
|
mAdapter.setCategory(mStagingCategory);
|
|
}
|
|
}
|
|
|
|
@WorkerThread
|
|
void updateCategory() {
|
|
final DashboardCategory category = mDashboardFeatureProvider.getTilesForCategory(
|
|
CategoryKey.CATEGORY_HOMEPAGE);
|
|
mSummaryLoader.updateSummaryToCache(category);
|
|
mStagingCategory = category;
|
|
if (mSuggestionControllerMixin == null) {
|
|
ThreadUtils.postOnMainThread(() -> mAdapter.setCategory(mStagingCategory));
|
|
return;
|
|
}
|
|
if (mSuggestionControllerMixin.isSuggestionLoaded()) {
|
|
Log.d(TAG, "Suggestion has loaded, setting suggestion/category");
|
|
ThreadUtils.postOnMainThread(() -> {
|
|
if (mStagingSuggestions != null) {
|
|
mAdapter.setSuggestions(mStagingSuggestions);
|
|
}
|
|
mAdapter.setCategory(mStagingCategory);
|
|
});
|
|
} else {
|
|
Log.d(TAG, "Suggestion NOT loaded, delaying setCategory by " + MAX_WAIT_MILLIS + "ms");
|
|
mHandler.postDelayed(() -> mAdapter.setCategory(mStagingCategory), MAX_WAIT_MILLIS);
|
|
}
|
|
}
|
|
}
|