Bug 875750 - Provide a basic color picker for Android. r=mfinkle

This commit is contained in:
Wes Johnston 2013-12-11 15:51:01 -08:00
Родитель 8bc776ce98
Коммит 5ba16c0086
18 изменённых файлов: 342 добавлений и 5 удалений

Просмотреть файл

@ -166,7 +166,7 @@ pref("dom.experimental_forms", true);
pref("dom.forms.number", true);
// Don't enable <input type=color> yet as we don't have a color picker
// implemented for Android (bug 875750)
pref("dom.forms.color", false);
pref("dom.forms.color", true);
/* extension manager and xpinstall */
pref("xpinstall.whitelist.add", "addons.mozilla.org");

Просмотреть файл

@ -266,6 +266,7 @@ gbjar.sources += [
'preferences/SyncPreference.java',
'PrefsHelper.java',
'PrivateTab.java',
'prompts/ColorPickerInput.java',
'prompts/IconGridInput.java',
'prompts/Prompt.java',
'prompts/PromptInput.java',
@ -314,6 +315,7 @@ gbjar.sources += [
'widget/AllCapsTextView.java',
'widget/AnimatedHeightLayout.java',
'widget/ArrowPopup.java',
'widget/BasicColorPicker.java',
'widget/ButtonToast.java',
'widget/CheckableLinearLayout.java',
'widget/ClickableWhenDisabledEditText.java',
@ -430,6 +432,7 @@ ANDROID_RESFILES += [
'resources/drawable-hdpi/bookmark_folder_closed.png',
'resources/drawable-hdpi/bookmark_folder_opened.png',
'resources/drawable-hdpi/close.png',
'resources/drawable-hdpi/color_picker_row_bg.9.png',
'resources/drawable-hdpi/copy.png',
'resources/drawable-hdpi/cut.png',
'resources/drawable-hdpi/favicon.png',
@ -578,6 +581,7 @@ ANDROID_RESFILES += [
'resources/drawable-mdpi/bookmarkdefaults_favicon_addons.png',
'resources/drawable-mdpi/bookmarkdefaults_favicon_support.png',
'resources/drawable-mdpi/close.png',
'resources/drawable-mdpi/color_picker_row_bg.9.png',
'resources/drawable-mdpi/copy.png',
'resources/drawable-mdpi/cut.png',
'resources/drawable-mdpi/desktop_notification.png',
@ -718,6 +722,7 @@ ANDROID_RESFILES += [
'resources/drawable-xhdpi/bookmark_folder_closed.png',
'resources/drawable-xhdpi/bookmark_folder_opened.png',
'resources/drawable-xhdpi/close.png',
'resources/drawable-xhdpi/color_picker_row_bg.9.png',
'resources/drawable-xhdpi/copy.png',
'resources/drawable-xhdpi/cut.png',
'resources/drawable-xhdpi/favicon.png',
@ -818,6 +823,7 @@ ANDROID_RESFILES += [
'resources/drawable/action_bar_button.xml',
'resources/drawable/action_bar_button_inverse.xml',
'resources/drawable/bookmark_folder.xml',
'resources/drawable/color_picker_checkmark.xml',
'resources/drawable/divider_horizontal.xml',
'resources/drawable/divider_vertical.xml',
'resources/drawable/handle_end_level.xml',
@ -867,11 +873,13 @@ ANDROID_RESFILES += [
'resources/layout/arrow_popup.xml',
'resources/layout/autocomplete_list.xml',
'resources/layout/autocomplete_list_item.xml',
'resources/layout/basic_color_picker_dialog.xml',
'resources/layout/bookmark_edit.xml',
'resources/layout/bookmark_folder_row.xml',
'resources/layout/bookmark_item_row.xml',
'resources/layout/browser_search.xml',
'resources/layout/browser_toolbar.xml',
'resources/layout/color_picker_row.xml',
'resources/layout/datetime_picker.xml',
'resources/layout/doorhanger.xml',
'resources/layout/doorhanger_button.xml',

Просмотреть файл

@ -0,0 +1,63 @@
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; 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.gecko.prompts;
import org.mozilla.gecko.R;
import org.mozilla.gecko.widget.BasicColorPicker;
import org.json.JSONObject;
import android.content.Context;
import android.graphics.Color;
import android.view.View;
import android.view.LayoutInflater;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.LinearLayout.LayoutParams;
public class ColorPickerInput extends PromptInput {
public static final String INPUT_TYPE = "color";
public static final String LOGTAG = "GeckoColorPickerInput";
private boolean mShowAdvancedButton = true;
private int mInitialColor;
public ColorPickerInput(JSONObject obj) {
super(obj);
String init = obj.optString("value");
mInitialColor = Color.rgb(Integer.parseInt(init.substring(1,3), 16),
Integer.parseInt(init.substring(3,5), 16),
Integer.parseInt(init.substring(5,7), 16));
}
@Override
public View getView(Context context) throws UnsupportedOperationException {
LayoutInflater inflater = LayoutInflater.from(context);
mView = inflater.inflate(R.layout.basic_color_picker_dialog, null);
BasicColorPicker cp = (BasicColorPicker) mView.findViewById(R.id.colorpicker);
cp.setColor(mInitialColor);
return mView;
}
@Override
public String getValue() {
BasicColorPicker cp = (BasicColorPicker) mView.findViewById(R.id.colorpicker);
int color = cp.getColor();
return "#" + Integer.toHexString(color).substring(2);
}
@Override
public boolean getScrollable() {
return true;
}
@Override
public boolean canApplyInputStyle() {
return false;
}
}

Просмотреть файл

@ -9,6 +9,7 @@ import org.mozilla.gecko.util.GeckoEventResponder;
import org.mozilla.gecko.GeckoEvent;
import org.mozilla.gecko.util.ThreadUtils;
import org.mozilla.gecko.widget.DateTimePicker;
import org.mozilla.gecko.prompts.ColorPickerInput;
import org.mozilla.gecko.R;
import org.mozilla.gecko.GeckoAppShell;
@ -108,8 +109,11 @@ public class Prompt implements OnClickListener, OnCancelListener, OnItemClickLis
}
}
private View applyInputStyle(View view) {
view.setPadding(mInputPaddingSize, 0, mInputPaddingSize, 0);
private View applyInputStyle(View view, PromptInput input) {
// Don't add padding to color picker views
if (input.canApplyInputStyle()) {
view.setPadding(mInputPaddingSize, 0, mInputPaddingSize, 0);
}
return view;
}
@ -333,12 +337,14 @@ public class Prompt implements OnClickListener, OnCancelListener, OnItemClickLis
if (length == 1) {
root = mInputs[0].getView(mContext);
applyInputStyle(root, mInputs[0]);
scrollable |= mInputs[0].getScrollable();
} else if (length > 1) {
LinearLayout linearLayout = new LinearLayout(mContext);
linearLayout.setOrientation(LinearLayout.VERTICAL);
for (int i = 0; i < length; i++) {
View content = mInputs[i].getView(mContext);
applyInputStyle(content, mInputs[i]);
linearLayout.addView(content);
scrollable |= mInputs[i].getScrollable();
}
@ -346,11 +352,11 @@ public class Prompt implements OnClickListener, OnCancelListener, OnItemClickLis
}
if (scrollable) {
builder.setView(applyInputStyle(root));
builder.setView(root);
} else {
ScrollView view = new ScrollView(mContext);
view.addView(root);
builder.setView(applyInputStyle(view));
builder.setView(view);
}
} catch(Exception ex) {
Log.e(LOGTAG, "Error showing prompt inputs", ex);

Просмотреть файл

@ -350,6 +350,8 @@ public class PromptInput {
return new LabelInput(obj);
} else if (IconGridInput.INPUT_TYPE.equals(type)) {
return new IconGridInput(obj);
} else if (ColorPickerInput.INPUT_TYPE.equals(type)) {
return new ColorPickerInput(obj);
} else {
for (String dtType : DateTimeInput.INPUT_TYPES) {
if (dtType.equals(type)) {
@ -375,4 +377,8 @@ public class PromptInput {
public boolean getScrollable() {
return false;
}
public boolean canApplyInputStyle() {
return true;
}
}

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 218 B

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 212 B

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 224 B

Просмотреть файл

@ -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/. -->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="ring"
android:innerRadius="15dip"
android:thickness="4dip"
android:useLevel="false">
<solid android:color="@android:color/white"/>
</shape>

Просмотреть файл

@ -0,0 +1,21 @@
<?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/. -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:orientation="vertical">
<org.mozilla.gecko.widget.BasicColorPicker android:id="@+id/colorpicker"
android:layout_height="0dip"
android:layout_weight="1"
android:drawSelectorOnTop="true"
android:choiceMode="singleChoice"
android:divider="@android:color/transparent"
android:dividerHeight="0dip"
android:listSelector="#22FFFFFF"
android:layout_width="fill_parent"/>
</LinearLayout>

Просмотреть файл

@ -0,0 +1,13 @@
<?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/. -->
<CheckedTextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="@style/TextAppearance.Widget.TextView"
style="@style/Widget.ListItem"
android:background="@drawable/color_picker_row_bg"
android:checkMark="@android:color/transparent"/>

Просмотреть файл

@ -0,0 +1,139 @@
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; 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.gecko.widget;
import org.mozilla.gecko.R;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.ArrayAdapter;
import android.widget.AdapterView;
import android.widget.CheckedTextView;
import android.widget.ListView;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.TypedValue;
public class BasicColorPicker extends ListView {
private final static String LOGTAG = "GeckoBasicColorPicker";
private final static List<Integer> DEFAULT_COLORS = Arrays.asList(Color.rgb(215,57,32),
Color.rgb(255,134,5),
Color.rgb(255,203,19),
Color.rgb(95,173,71),
Color.rgb(84,201,168),
Color.rgb(33,161,222),
Color.rgb(16,36,87),
Color.rgb(91,32,103),
Color.rgb(212,221,228),
Color.BLACK);
private static Drawable mCheckDrawable = null;
private int mSelected = 0;
final private ColorPickerListAdapter mAdapter;
public BasicColorPicker(Context context) {
this(context, null);
}
public BasicColorPicker(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public BasicColorPicker(Context context, AttributeSet attrs, int style) {
this(context, attrs, style, DEFAULT_COLORS);
}
public BasicColorPicker(Context context, AttributeSet attrs, int style, List<Integer> colors) {
super(context, attrs, style);
mAdapter = new ColorPickerListAdapter(context, new ArrayList<Integer>(colors));
setAdapter(mAdapter);
setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
mSelected = position;
mAdapter.notifyDataSetChanged();
}
});
}
public int getColor() {
return mAdapter.getItem(mSelected);
}
public void setColor(int color) {
if (!DEFAULT_COLORS.contains(color)) {
mSelected = mAdapter.getCount();
mAdapter.add(color);
} else {
mSelected = DEFAULT_COLORS.indexOf(color);
}
setSelection(mSelected);
mAdapter.notifyDataSetChanged();
}
private Drawable getCheckDrawable() {
if (mCheckDrawable == null) {
Resources res = getContext().getResources();
TypedValue typedValue = new TypedValue();
getContext().getTheme().resolveAttribute(android.R.attr.listPreferredItemHeight, typedValue, true);
DisplayMetrics metrics = new android.util.DisplayMetrics();
((WindowManager)getContext().getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getMetrics(metrics);
int height = (int) typedValue.getDimension(metrics);
Drawable background = res.getDrawable(R.drawable.color_picker_row_bg);
Rect r = new Rect();
background.getPadding(r);
height -= r.top + r.bottom;
mCheckDrawable = res.getDrawable(R.drawable.color_picker_checkmark);
mCheckDrawable.setBounds(0, 0, height, height);
}
return mCheckDrawable;
}
private class ColorPickerListAdapter extends ArrayAdapter<Integer> {
private final List<Integer> mColors;
public ColorPickerListAdapter(Context context, List<Integer> colors) {
super(context, R.layout.color_picker_row, colors);
mColors = colors;
}
public View getView(int position, View convertView, ViewGroup parent) {
View v = super.getView(position, convertView, parent);
Drawable d = v.getBackground();
d.setColorFilter(getItem(position), PorterDuff.Mode.MULTIPLY);
v.setBackground(d);
Drawable check = null;
CheckedTextView checked = ((CheckedTextView) v);
if (mSelected == position) {
check = getCheckDrawable();
}
checked.setCompoundDrawables(check, null, null, null);
checked.setText("");
return v;
}
}
}

Просмотреть файл

@ -0,0 +1,51 @@
/* 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/. */
const Ci = Components.interfaces;
const Cu = Components.utils;
const Cc = Components.classes;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/Prompt.jsm");
function ColorPicker() {
}
ColorPicker.prototype = {
_initial: 0,
_domWin: null,
_title: "",
get strings() {
delete this.strings;
return this.strings = Services.strings.createBundle("chrome://browser/locale/browser.properties");
},
init: function(aParent, aTitle, aInitial) {
this._domWin = aParent;
this._initial = aInitial;
this._title = aTitle;
},
open: function(aCallback) {
let p = new Prompt({ title: this._title,
buttons: [
this.strings.GetStringFromName("inputWidgetHelper.set"),
this.strings.GetStringFromName("inputWidgetHelper.cancel")
] })
.addColorPicker({ value: this._initial })
.show((data) => {
if (data.button == 0)
aCallback.done(data.color0);
else
aCallback.done(this._initial);
});
},
classID: Components.ID("{430b987f-bb9f-46a3-99a5-241749220b29}"),
QueryInterface: XPCOMUtils.generateQI([Ci.nsIColorPicker])
};
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([ColorPicker]);

Просмотреть файл

@ -105,3 +105,7 @@ component {a78d7e59-b558-4321-a3d6-dffe2f1e76dd} Snippets.js
contract @mozilla.org/snippets;1 {a78d7e59-b558-4321-a3d6-dffe2f1e76dd}
category profile-after-change Snippets @mozilla.org/snippets;1
category update-timer Snippets @mozilla.org/snippets;1,getService,snippets-update-timer,browser.snippets.updateInterval,86400
# ColorPicker.js
component {430b987f-bb9f-46a3-99a5-241749220b29} ColorPicker.js
contract @mozilla.org/colorpicker;1 {430b987f-bb9f-46a3-99a5-241749220b29}

Просмотреть файл

@ -13,6 +13,7 @@ XPIDL_MODULE = 'MobileComponents'
EXTRA_COMPONENTS += [
'AddonUpdateService.js',
'BlocklistPrompt.js',
'ColorPicker.js',
'ContentDispatchChooser.js',
'ContentPermissionPrompt.js',
'DownloadManagerUI.js',

Просмотреть файл

@ -558,6 +558,7 @@ bin/components/@DLL_PREFIX@nkgnomevfs@DLL_SUFFIX@
@BINPATH@/components/AddonUpdateService.js
@BINPATH@/components/BlocklistPrompt.js
@BINPATH@/components/BrowserCLH.js
@BINPATH@/components/ColorPicker.js
@BINPATH@/components/ContentDispatchChooser.js
@BINPATH@/components/ContentPermissionPrompt.js
@BINPATH@/components/DirectoryProvider.js

Просмотреть файл

@ -117,6 +117,14 @@ Prompt.prototype = {
});
},
addColorPicker: function(aOptions) {
return this._addInput({
type: "color",
value: aOptions.value,
id: aOptions.id
});
},
addLabel: function(aOptions) {
return this._addInput({
type: "label",

Просмотреть файл

@ -397,6 +397,10 @@ nsLookAndFeel::GetIntImpl(IntID aID, int32_t &aResult)
aResult = 1;
break;
case eIntID_ColorPickerAvailable:
aResult = 1;
break;
case eIntID_WindowsDefaultTheme:
case eIntID_WindowsThemeIdentifier:
case eIntID_OperatingSystemVersionIdentifier: