Bug 1035642 - Add search widget. r=mfinkle,margaret
124
mobile/android/search/java/org/mozilla/search/SearchWidget.java
Normal file
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -13,8 +13,28 @@
|
||||
|
||||
<category android:name="android.intent.category.DEFAULT"/>
|
||||
</intent-filter>
|
||||
|
||||
</activity>
|
||||
|
||||
<!-- Basic launcher widget. -->
|
||||
<receiver android:name="org.mozilla.search.SearchWidget"
|
||||
android:label="@string/search_widget_name">
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
|
||||
</intent-filter>
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="org.mozilla.widget.LAUNCH_BROWSER"/>
|
||||
</intent-filter>
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="org.mozilla.widget.LAUNCH_SEARCH"/>
|
||||
</intent-filter>
|
||||
|
||||
<meta-data android:name="android.appwidget.provider" android:resource="@xml/search_widget_info" />
|
||||
</receiver>
|
||||
|
||||
<activity
|
||||
android:name="org.mozilla.search.SearchPreferenceActivity"
|
||||
android:label="@string/search_pref_title"
|
||||
|
BIN
mobile/android/search/res/drawable-hdpi/ic_widget_new_tab.png
Normal file
After Width: | Height: | Size: 141 B |
BIN
mobile/android/search/res/drawable-hdpi/widget_active_bg.9.png
Normal file
After Width: | Height: | Size: 2.0 KiB |
BIN
mobile/android/search/res/drawable-hdpi/widget_bg.9.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
mobile/android/search/res/drawable-mdpi/ic_widget_new_tab.png
Normal file
After Width: | Height: | Size: 140 B |
BIN
mobile/android/search/res/drawable-mdpi/widget_active_bg.9.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
mobile/android/search/res/drawable-mdpi/widget_bg.9.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
mobile/android/search/res/drawable-xhdpi/ic_widget_new_tab.png
Normal file
After Width: | Height: | Size: 144 B |
BIN
mobile/android/search/res/drawable-xhdpi/widget_active_bg.9.png
Normal file
After Width: | Height: | Size: 3.0 KiB |
BIN
mobile/android/search/res/drawable-xhdpi/widget_bg.9.png
Normal file
After Width: | Height: | Size: 2.6 KiB |
15
mobile/android/search/res/drawable/search_widget_button.xml
Normal file
@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 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/. -->
|
||||
|
||||
<!-- Drawable used for buttons in the launch widget -->
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:constantSize="true">
|
||||
|
||||
<item android:state_pressed="true"
|
||||
android:drawable="@drawable/widget_active_bg"/>
|
||||
|
||||
<item android:drawable="@drawable/widget_bg"/>
|
||||
|
||||
</selector>
|
71
mobile/android/search/res/layout/search_widget.xml
Normal file
@ -0,0 +1,71 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 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/. -->
|
||||
|
||||
<!-- A homescreen widget for launching Fennec or the search activity. We can't use styles in here
|
||||
so make sure any changes you make are also made to launch_widget.xml which doesn't have
|
||||
the search widget button. -->
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/widget_header_height">
|
||||
|
||||
<!-- Wrap in a linear layout to center the text in a flexible space. We use a negative margin
|
||||
to extend this into the firefox logo so that the button background appears to come from behind the logo, but
|
||||
highlights correctly when tapped. -->
|
||||
<LinearLayout android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_toLeftOf="@+id/logo_button"
|
||||
android:layout_marginRight="@dimen/widget_button_offset"
|
||||
android:paddingRight="@dimen/widget_button_padding"
|
||||
android:gravity="center"
|
||||
android:background="@drawable/search_widget_button"
|
||||
android:orientation="horizontal"
|
||||
android:id="@+id/search_button">
|
||||
|
||||
<TextView android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:drawableLeft="@drawable/ic_url_bar_search"
|
||||
android:drawablePadding="@dimen/widget_drawable_padding"
|
||||
android:text="@string/search_widget_button_label"
|
||||
android:contentDescription="@string/search_widget_button_label"
|
||||
android:gravity="center"
|
||||
android:textSize="@dimen/widget_text_size"
|
||||
android:textColor="@color/text_color_primary"
|
||||
android:id="@+id/search_button_label"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout android:layout_width="match_parent"
|
||||
android:layout_toRightOf="@+id/logo_button"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginLeft="@dimen/widget_button_offset"
|
||||
android:paddingLeft="@dimen/widget_button_padding"
|
||||
android:layout_centerVertical="true"
|
||||
android:gravity="center"
|
||||
android:background="@drawable/search_widget_button"
|
||||
android:orientation="horizontal"
|
||||
android:id="@+id/new_tab_button">
|
||||
|
||||
<TextView android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:drawableLeft="@drawable/ic_widget_new_tab"
|
||||
android:drawablePadding="@dimen/widget_drawable_padding"
|
||||
android:gravity="center"
|
||||
android:text="@string/new_tab"
|
||||
android:contentDescription="@string/new_tab"
|
||||
android:textSize="@dimen/widget_text_size"
|
||||
android:textColor="@color/text_color_primary"
|
||||
android:id="@+id/new_tab_button_label"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<!-- The logo. adjustViewBounds is required for the buttons above to stretch underneath the logo. -->
|
||||
<ImageView android:id="@+id/logo_button"
|
||||
android:layout_centerInParent="true"
|
||||
android:adjustViewBounds="true"
|
||||
android:layout_width="@dimen/widget_header_height"
|
||||
android:layout_height="match_parent"
|
||||
android:src="@drawable/icon"/>
|
||||
|
||||
</RelativeLayout>
|
@ -23,4 +23,11 @@
|
||||
<dimen name="card_padding_x">38dp</dimen>
|
||||
<dimen name="card_padding_y">23dp</dimen>
|
||||
|
||||
<!-- Widget Buttons -->
|
||||
<dimen name="widget_header_height">70dp</dimen>
|
||||
<dimen name="widget_button_offset">-50dp</dimen>
|
||||
<dimen name="widget_button_padding">45dp</dimen>
|
||||
<dimen name="widget_text_size">15sp</dimen>
|
||||
<dimen name="widget_drawable_padding">2dp</dimen>
|
||||
|
||||
</resources>
|
||||
|
12
mobile/android/search/res/xml/search_widget_info.xml
Normal file
@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 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/. -->
|
||||
|
||||
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:minWidth="300dp"
|
||||
android:minHeight="40dp"
|
||||
android:label="@string/search_widget_name"
|
||||
android:widgetCategory="home_screen"
|
||||
android:previewImage="@drawable/launcher_widget"
|
||||
android:initialLayout="@layout/search_widget"/>
|
@ -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',
|
||||
]
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
<!ENTITY search_jump_arrow '↖'>
|
||||
|
||||
<!ENTITY search_app_name 'Firefox Search'>
|
||||
<!ENTITY search_app_name '&brandShortName; Search'>
|
||||
<!ENTITY search_for_something 'Search for something'>
|
||||
|
||||
<!ENTITY search_pref_title 'Settings'>
|
||||
@ -12,3 +12,6 @@
|
||||
<!ENTITY search_pref_clear_history_dialog_message 'Delete all search history from this device?'>
|
||||
<!ENTITY search_pref_clear_history_title 'Clear search history'>
|
||||
<!ENTITY search_pref_button_content_description 'Settings'>
|
||||
|
||||
<!ENTITY search_widget_button_label 'Search'>
|
||||
|
||||
|
@ -8,3 +8,6 @@
|
||||
<string name="search_pref_clear_history_dialog_message">&search_pref_clear_history_dialog_message;</string>
|
||||
<string name="search_pref_clear_history_title">&search_pref_clear_history_title;</string>
|
||||
<string name="search_pref_button_content_description">&search_pref_button_content_description;</string>
|
||||
|
||||
<string name="search_widget_name">&search_app_name;</string>
|
||||
<string name="search_widget_button_label">&search_widget_button_label;</string>
|
||||
|