c39ff736c0
Change-Id: I0db112e3dc60cb59db10fde3d9088c11a09fae8c
266 lines
11 KiB
Java
266 lines
11 KiB
Java
/*
|
|
* 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.launcher3;
|
|
|
|
import android.app.Activity;
|
|
import android.app.Fragment;
|
|
import android.app.SearchManager;
|
|
import android.appwidget.AppWidgetManager;
|
|
import android.appwidget.AppWidgetProviderInfo;
|
|
import android.content.BroadcastReceiver;
|
|
import android.content.ComponentName;
|
|
import android.content.Context;
|
|
import android.content.Intent;
|
|
import android.content.IntentFilter;
|
|
import android.content.SharedPreferences;
|
|
import android.graphics.Rect;
|
|
import android.os.Bundle;
|
|
import android.util.AttributeSet;
|
|
import android.view.LayoutInflater;
|
|
import android.view.View;
|
|
import android.view.ViewGroup;
|
|
import android.widget.FrameLayout;
|
|
|
|
import com.android.launcher3.compat.AppWidgetManagerCompat;
|
|
|
|
/**
|
|
* A frame layout which contains a QSB. This internally uses fragment to bind the view, which
|
|
* allows it to contain the logic for {@link Fragment#startActivityForResult(Intent, int)}.
|
|
*/
|
|
public class QsbContainerView extends FrameLayout {
|
|
|
|
public QsbContainerView(Context context) {
|
|
super(context);
|
|
}
|
|
|
|
public QsbContainerView(Context context, AttributeSet attrs) {
|
|
super(context, attrs);
|
|
}
|
|
|
|
public QsbContainerView(Context context, AttributeSet attrs, int defStyleAttr) {
|
|
super(context, attrs, defStyleAttr);
|
|
}
|
|
|
|
@Override
|
|
public void setPadding(int left, int top, int right, int bottom) {
|
|
super.setPadding(0, 0, 0, 0);
|
|
}
|
|
|
|
/**
|
|
* A fragment to display the QSB.
|
|
*/
|
|
public static class QsbFragment extends Fragment implements View.OnClickListener {
|
|
|
|
private static final int REQUEST_BIND_QSB = 1;
|
|
private static final String QSB_WIDGET_ID = "qsb_widget_id";
|
|
|
|
private static int sSavedWidgetId = -1;
|
|
|
|
private AppWidgetProviderInfo mWidgetInfo;
|
|
private LauncherAppWidgetHostView mQsb;
|
|
|
|
private BroadcastReceiver mRebindReceiver = new BroadcastReceiver() {
|
|
@Override
|
|
public void onReceive(Context context, Intent intent) {
|
|
rebindFragment();
|
|
}
|
|
};
|
|
|
|
@Override
|
|
public void onCreate(Bundle savedInstanceState) {
|
|
super.onCreate(savedInstanceState);
|
|
|
|
IntentFilter filter = new IntentFilter(Launcher.ACTION_APPWIDGET_HOST_RESET);
|
|
filter.addAction(SearchManager.INTENT_GLOBAL_SEARCH_ACTIVITY_CHANGED);
|
|
getActivity().registerReceiver(mRebindReceiver, filter);
|
|
}
|
|
|
|
private FrameLayout mWrapper;
|
|
|
|
@Override
|
|
public View onCreateView(
|
|
LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
|
|
|
if (savedInstanceState != null) {
|
|
sSavedWidgetId = savedInstanceState.getInt(QSB_WIDGET_ID, -1);
|
|
}
|
|
mWrapper = new FrameLayout(getActivity());
|
|
mWrapper.addView(createQsb(inflater, mWrapper));
|
|
return mWrapper;
|
|
}
|
|
|
|
private View createQsb(LayoutInflater inflater, ViewGroup container) {
|
|
Launcher launcher = (Launcher) getActivity();
|
|
mWidgetInfo = getSearchWidgetProvider(launcher);
|
|
if (mWidgetInfo == null) {
|
|
// There is no search provider, just show the default widget.
|
|
return getDefaultView(inflater, container, false);
|
|
} else {
|
|
mWidgetInfo = LauncherAppWidgetProviderInfo.fromProviderInfo(launcher, mWidgetInfo);
|
|
}
|
|
|
|
SharedPreferences prefs = Utilities.getPrefs(launcher);
|
|
AppWidgetManagerCompat widgetManager = AppWidgetManagerCompat.getInstance(launcher);
|
|
LauncherAppWidgetHost widgetHost = launcher.getAppWidgetHost();
|
|
InvariantDeviceProfile idp = LauncherAppState.getInstance().getInvariantDeviceProfile();
|
|
|
|
Bundle opts = new Bundle();
|
|
Rect size = AppWidgetResizeFrame.getWidgetSizeRanges(launcher, idp.numColumns, 1, null);
|
|
opts.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH, size.left);
|
|
opts.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT, size.top);
|
|
opts.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH, size.right);
|
|
opts.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT, size.bottom);
|
|
|
|
int widgetId = prefs.getInt(QSB_WIDGET_ID, -1);
|
|
AppWidgetProviderInfo widgetInfo = widgetManager.getAppWidgetInfo(widgetId);
|
|
boolean isWidgetBound = (widgetInfo != null) &&
|
|
widgetInfo.provider.equals(mWidgetInfo.provider);
|
|
|
|
if (!isWidgetBound) {
|
|
// widgetId is already bound and its not the correct provider.
|
|
// Delete the widget id.
|
|
if (widgetId > -1) {
|
|
widgetHost.deleteAppWidgetId(widgetId);
|
|
widgetId = -1;
|
|
}
|
|
|
|
widgetId = widgetHost.allocateAppWidgetId();
|
|
isWidgetBound = widgetManager.bindAppWidgetIdIfAllowed(widgetId, mWidgetInfo, opts);
|
|
if (!isWidgetBound) {
|
|
widgetHost.deleteAppWidgetId(widgetId);
|
|
widgetId = -1;
|
|
}
|
|
}
|
|
|
|
if (isWidgetBound) {
|
|
mQsb = (LauncherAppWidgetHostView)
|
|
widgetHost.createView(launcher, widgetId, mWidgetInfo);
|
|
mQsb.setId(R.id.qsb_widget);
|
|
mQsb.mErrorViewId = R.layout.qsb_default_view;
|
|
|
|
if (!Utilities.containsAll(AppWidgetManager.getInstance(launcher)
|
|
.getAppWidgetOptions(widgetId), opts)) {
|
|
mQsb.updateAppWidgetOptions(opts);
|
|
}
|
|
mQsb.setPadding(0, 0, 0, 0);
|
|
return mQsb;
|
|
}
|
|
|
|
// Return a default widget with setup icon.
|
|
return getDefaultView(inflater, container, true);
|
|
}
|
|
|
|
@Override
|
|
public void onClick(View view) {
|
|
if (view.getId() == R.id.btn_qsb_search) {
|
|
getActivity().startSearch("", false, null, true);
|
|
} else if (view.getId() == R.id.btn_qsb_setup) {
|
|
// Allocate a new widget id for QSB
|
|
sSavedWidgetId = ((Launcher) getActivity())
|
|
.getAppWidgetHost().allocateAppWidgetId();
|
|
// Start intent for bind the widget
|
|
Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_BIND);
|
|
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, sSavedWidgetId);
|
|
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_PROVIDER, mWidgetInfo.provider);
|
|
startActivityForResult(intent, REQUEST_BIND_QSB);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onSaveInstanceState(Bundle outState) {
|
|
super.onSaveInstanceState(outState);
|
|
outState.putInt(QSB_WIDGET_ID, sSavedWidgetId);
|
|
}
|
|
|
|
@Override
|
|
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
|
if (requestCode == REQUEST_BIND_QSB) {
|
|
if (resultCode == Activity.RESULT_OK) {
|
|
int widgetId = data.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
|
|
sSavedWidgetId);
|
|
Utilities.getPrefs(getActivity()).edit().putInt(QSB_WIDGET_ID, widgetId).apply();
|
|
sSavedWidgetId = -1;
|
|
rebindFragment();
|
|
} else if (sSavedWidgetId != -1) {
|
|
((Launcher) getActivity()).getAppWidgetHost().deleteAppWidgetId(sSavedWidgetId);
|
|
sSavedWidgetId = -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onResume() {
|
|
super.onResume();
|
|
if (mQsb != null && mQsb.isReinflateRequired()) {
|
|
rebindFragment();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onDestroy() {
|
|
getActivity().unregisterReceiver(mRebindReceiver);
|
|
super.onDestroy();
|
|
}
|
|
|
|
private void rebindFragment() {
|
|
if (mWrapper != null && getActivity() != null) {
|
|
mWrapper.removeAllViews();
|
|
mWrapper.addView(createQsb(getActivity().getLayoutInflater(), mWrapper));
|
|
}
|
|
}
|
|
|
|
private View getDefaultView(LayoutInflater inflater, ViewGroup parent, boolean showSetup) {
|
|
View v = inflater.inflate(R.layout.qsb_default_view, parent, false);
|
|
if (showSetup) {
|
|
View setupButton = v.findViewById(R.id.btn_qsb_setup);
|
|
setupButton.setVisibility(View.VISIBLE);
|
|
setupButton.setOnClickListener(this);
|
|
}
|
|
v.findViewById(R.id.btn_qsb_search).setOnClickListener(this);
|
|
return v;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns a widget with category {@link AppWidgetProviderInfo#WIDGET_CATEGORY_SEARCHBOX}
|
|
* provided by the same package which is set to be global search activity.
|
|
* If widgetCategory is not supported, or no such widget is found, returns the first widget
|
|
* provided by the package.
|
|
*/
|
|
public static AppWidgetProviderInfo getSearchWidgetProvider(Context context) {
|
|
SearchManager searchManager =
|
|
(SearchManager) context.getSystemService(Context.SEARCH_SERVICE);
|
|
ComponentName searchComponent = searchManager.getGlobalSearchActivity();
|
|
if (searchComponent == null) return null;
|
|
String providerPkg = searchComponent.getPackageName();
|
|
|
|
AppWidgetProviderInfo defaultWidgetForSearchPackage = null;
|
|
|
|
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
|
|
for (AppWidgetProviderInfo info : appWidgetManager.getInstalledProviders()) {
|
|
if (info.provider.getPackageName().equals(providerPkg) && info.configure == null) {
|
|
if ((info.widgetCategory & AppWidgetProviderInfo.WIDGET_CATEGORY_SEARCHBOX) != 0) {
|
|
return info;
|
|
} else if (defaultWidgetForSearchPackage == null) {
|
|
defaultWidgetForSearchPackage = info;
|
|
}
|
|
}
|
|
}
|
|
return defaultWidgetForSearchPackage;
|
|
}
|
|
}
|