blob: 54588ec98fc91a3624d8d42c5fa66f71b5da0a6f [file] [log] [blame]
/*
* Copyright (C) 2022 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.quicksearchbox
import android.app.PendingIntent
import android.app.SearchManager
import android.appwidget.AppWidgetManager
import android.content.BroadcastReceiver
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.util.Log
import android.view.View
import android.widget.RemoteViews
import com.android.common.Search
/** Search widget provider. */
class SearchWidgetProvider : BroadcastReceiver() {
@Override
override fun onReceive(context: Context?, intent: Intent) {
if (DBG) Log.d(TAG, "onReceive(" + intent.toUri(0).toString() + ")")
val action: String? = intent.getAction()
if (AppWidgetManager.ACTION_APPWIDGET_ENABLED.equals(action)) {
// nothing needs doing
} else if (AppWidgetManager.ACTION_APPWIDGET_UPDATE.equals(action)) {
updateSearchWidgets(context)
} else {
if (DBG) Log.d(TAG, "Unhandled intent action=$action")
}
}
private class SearchWidgetState(private val mAppWidgetId: Int) {
private var mQueryTextViewIntent: Intent? = null
private var mVoiceSearchIntent: Intent? = null
fun setQueryTextViewIntent(queryTextViewIntent: Intent?) {
mQueryTextViewIntent = queryTextViewIntent
}
fun setVoiceSearchIntent(voiceSearchIntent: Intent?) {
mVoiceSearchIntent = voiceSearchIntent
}
fun updateWidget(context: Context?, appWidgetMgr: AppWidgetManager) {
if (DBG) Log.d(TAG, "Updating appwidget $mAppWidgetId")
val views = RemoteViews(context!!.getPackageName(), R.layout.search_widget)
setOnClickActivityIntent(context, views, R.id.search_widget_text, mQueryTextViewIntent)
// Voice Search button
if (mVoiceSearchIntent != null) {
setOnClickActivityIntent(context, views, R.id.search_widget_voice_btn, mVoiceSearchIntent)
views.setViewVisibility(R.id.search_widget_voice_btn, View.VISIBLE)
} else {
views.setViewVisibility(R.id.search_widget_voice_btn, View.GONE)
}
appWidgetMgr.updateAppWidget(mAppWidgetId, views)
}
private fun setOnClickActivityIntent(
context: Context?,
views: RemoteViews,
viewId: Int,
intent: Intent?
) {
intent?.setPackage(context?.getPackageName())
val pendingIntent: PendingIntent = PendingIntent.getActivity(context, 0, intent, 0)
views.setOnClickPendingIntent(viewId, pendingIntent)
}
}
companion object {
private const val DBG = false
private const val TAG = "QSB.SearchWidgetProvider"
/** The [Search.SOURCE] value used when starting searches from the search widget. */
private const val WIDGET_SEARCH_SOURCE = "launcher-widget"
private fun getSearchWidgetStates(context: Context?): Array<SearchWidgetState?> {
val appWidgetManager: AppWidgetManager = AppWidgetManager.getInstance(context)
val appWidgetIds: IntArray = appWidgetManager.getAppWidgetIds(myComponentName(context))
val states: Array<SearchWidgetState?> = arrayOfNulls(appWidgetIds.size)
for (i in appWidgetIds.indices) {
states[i] = getSearchWidgetState(context, appWidgetIds[i])
}
return states
}
/** Updates all search widgets. */
@JvmStatic
fun updateSearchWidgets(context: Context?) {
if (DBG) Log.d(TAG, "updateSearchWidgets")
val states: Array<SearchWidgetState?> = getSearchWidgetStates(context)
for (state in states) {
state?.updateWidget(context, AppWidgetManager.getInstance(context))
}
}
/** Gets the component name of this search widget provider. */
private fun myComponentName(context: Context?): ComponentName {
val pkg: String = context!!.getPackageName()
val cls = "$pkg.SearchWidgetProvider"
return ComponentName(pkg, cls)
}
private fun createQsbActivityIntent(
context: Context?,
action: String,
widgetAppData: Bundle
): Intent {
val qsbIntent = Intent(action)
qsbIntent.setPackage(context?.getPackageName())
qsbIntent.setFlags(
Intent.FLAG_ACTIVITY_NEW_TASK or
Intent.FLAG_ACTIVITY_CLEAR_TOP or
Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
)
qsbIntent.putExtra(SearchManager.APP_DATA, widgetAppData)
return qsbIntent
}
private fun getSearchWidgetState(context: Context?, appWidgetId: Int): SearchWidgetState {
if (DBG) Log.d(TAG, "Creating appwidget state $appWidgetId")
val state: SearchWidgetState = SearchWidgetState(appWidgetId)
val widgetAppData = Bundle()
widgetAppData.putString(Search.SOURCE, WIDGET_SEARCH_SOURCE)
// Text field click
val qsbIntent: Intent =
createQsbActivityIntent(context, SearchManager.INTENT_ACTION_GLOBAL_SEARCH, widgetAppData)
state.setQueryTextViewIntent(qsbIntent)
// Voice search button
val voiceSearchIntent: Intent? = getVoiceSearchIntent(context, widgetAppData)
state.setVoiceSearchIntent(voiceSearchIntent)
return state
}
private fun getVoiceSearchIntent(context: Context?, widgetAppData: Bundle): Intent? {
val voiceSearch: VoiceSearch? = QsbApplication[context].voiceSearch
return voiceSearch?.createVoiceWebSearchIntent(widgetAppData)
}
}
}