diff --git a/mobile/android/search/java/org/mozilla/search/SearchWidget.java b/mobile/android/search/java/org/mozilla/search/SearchWidget.java new file mode 100644 index 00000000000..88d8ea02247 --- /dev/null +++ b/mobile/android/search/java/org/mozilla/search/SearchWidget.java @@ -0,0 +1,124 @@ +/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package org.mozilla.search; + +import org.mozilla.gecko.AppConstants; + +import android.annotation.SuppressLint; +import android.app.PendingIntent; +import android.appwidget.AppWidgetManager; +import android.appwidget.AppWidgetProvider; +import android.content.Context; +import android.content.Intent; +import android.net.Uri; +import android.os.Build; +import android.os.Bundle; +import android.widget.RemoteViews; +import android.util.Log; + +/* Provides a really simple widget with two buttons, one to launch Fennec + * and one to launch the search activity. All intents are actually sent back + * here and then forwarded on to start the real activity. */ +public class SearchWidget extends AppWidgetProvider { + final private static String LOGTAG = "GeckoSearchWidget"; + + final public static String ACTION_LAUNCH_BROWSER = "org.mozilla.widget.LAUNCH_BROWSER"; + final public static String ACTION_LAUNCH_SEARCH = "org.mozilla.widget.LAUNCH_SEARCH"; + + @SuppressLint("NewApi") + @Override + public void onUpdate(final Context context, final AppWidgetManager manager, final int[] ids) { + for (int id : ids) { + final Bundle bundle; + if (AppConstants.Versions.feature16Plus) { + bundle = manager.getAppWidgetOptions(id); + } else { + bundle = null; + } + addView(manager, context, id, bundle); + } + + super.onUpdate(context, manager, ids); + } + + @SuppressLint("NewApi") + @Override + public void onAppWidgetOptionsChanged(final Context context, + final AppWidgetManager manager, + final int id, + final Bundle options) { + addView(manager, context, id, options); + if (AppConstants.Versions.feature16Plus) { + super.onAppWidgetOptionsChanged(context, manager, id, options); + } + } + + @Override + public void onReceive(final Context context, final Intent intent) { + // This will hold the intent to redispatch + final Intent redirect; + Log.i(LOGTAG, "Got intent " + intent.getAction()); + if (intent.getAction().equals(ACTION_LAUNCH_BROWSER)) { + redirect = buildRedirectIntent(Intent.ACTION_VIEW, + AppConstants.ANDROID_PACKAGE_NAME, + AppConstants.BROWSER_INTENT_CLASS_NAME, + intent); + } else if (intent.getAction().equals(ACTION_LAUNCH_SEARCH)) { + redirect = buildRedirectIntent(Intent.ACTION_VIEW, + AppConstants.SEARCH_PACKAGE_NAME, + AppConstants.SEARCH_INTENT_CLASS_NAME, + intent); + } else { + redirect = null; + } + + if (redirect != null) { + try { + context.startActivity(redirect); + } catch(Exception ex) { + // When this is built stand alone, its hardcoded to try and launch nightly. + // If that fails, just fire a generic VIEW intent. + Intent redirect2 = buildRedirectIntent(Intent.ACTION_VIEW, null, null, intent); + context.startActivity(redirect2); + } + } + + super.onReceive(context, intent); + } + + // Utility to create the view for this widget and attach any event listeners to it + private void addView(final AppWidgetManager manager, final Context context, final int id, final Bundle options) { + final RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.search_widget); + + addClickIntent(context, views, R.id.search_button, ACTION_LAUNCH_SEARCH); + addClickIntent(context, views, R.id.new_tab_button, ACTION_LAUNCH_BROWSER); + // Clicking the logo also launches the browser + addClickIntent(context, views, R.id.logo_button, ACTION_LAUNCH_BROWSER); + + manager.updateAppWidget(id, views); + } + + // Utility for adding a pending intent to be fired when a View is clicked. + private void addClickIntent(final Context context, final RemoteViews views, final int viewId, final String action) { + final Intent intent = new Intent(context, SearchWidget.class); + intent.setAction(action); + intent.setData(Uri.parse("about:home")); + final PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, 0); + views.setOnClickPendingIntent(viewId, pendingIntent); + } + + // Utility for building an intent to be redispatched (i.e. to launch the browser or the search intent). + private Intent buildRedirectIntent(final String action, final String pkg, final String className, final Intent source) { + final Intent activity = new Intent(action); + if (pkg != null && className != null) { + activity.setClassName(pkg, className); + } + activity.setData(source.getData()); + activity.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + return activity; + } + +} diff --git a/mobile/android/search/manifests/SearchAndroidManifest_activities.xml.in b/mobile/android/search/manifests/SearchAndroidManifest_activities.xml.in index 12589f76224..672e6353b9d 100644 --- a/mobile/android/search/manifests/SearchAndroidManifest_activities.xml.in +++ b/mobile/android/search/manifests/SearchAndroidManifest_activities.xml.in @@ -13,8 +13,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mobile/android/search/res/layout/search_widget.xml b/mobile/android/search/res/layout/search_widget.xml new file mode 100644 index 00000000000..2ad9d50d27d --- /dev/null +++ b/mobile/android/search/res/layout/search_widget.xml @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mobile/android/search/res/values/search_dimens.xml b/mobile/android/search/res/values/search_dimens.xml index 80e4deadcac..444807eb973 100644 --- a/mobile/android/search/res/values/search_dimens.xml +++ b/mobile/android/search/res/values/search_dimens.xml @@ -23,4 +23,11 @@ 38dp 23dp + + 70dp + -50dp + 45dp + 15sp + 2dp + diff --git a/mobile/android/search/res/xml/search_widget_info.xml b/mobile/android/search/res/xml/search_widget_info.xml new file mode 100644 index 00000000000..f837c4a208e --- /dev/null +++ b/mobile/android/search/res/xml/search_widget_info.xml @@ -0,0 +1,12 @@ + + + + diff --git a/mobile/android/search/search_activity_sources.mozbuild b/mobile/android/search/search_activity_sources.mozbuild index 517cd0ba13f..d84d243d201 100644 --- a/mobile/android/search/search_activity_sources.mozbuild +++ b/mobile/android/search/search_activity_sources.mozbuild @@ -16,4 +16,5 @@ search_activity_sources = [ 'java/org/mozilla/search/PostSearchFragment.java', 'java/org/mozilla/search/PreSearchFragment.java', 'java/org/mozilla/search/SearchPreferenceActivity.java', + 'java/org/mozilla/search/SearchWidget.java', ] diff --git a/mobile/android/search/strings/search_strings.dtd b/mobile/android/search/strings/search_strings.dtd index 425ed073ef9..1b4d2e251a9 100644 --- a/mobile/android/search/strings/search_strings.dtd +++ b/mobile/android/search/strings/search_strings.dtd @@ -4,7 +4,7 @@ - + @@ -12,3 +12,6 @@ + + + diff --git a/mobile/android/search/strings/search_strings.xml.in b/mobile/android/search/strings/search_strings.xml.in index ee0b866166e..6c8e45b0b73 100644 --- a/mobile/android/search/strings/search_strings.xml.in +++ b/mobile/android/search/strings/search_strings.xml.in @@ -8,3 +8,6 @@ &search_pref_clear_history_dialog_message; &search_pref_clear_history_title; &search_pref_button_content_description; + + &search_app_name; + &search_widget_button_label;