зеркало из https://github.com/mozilla/gecko-dev.git
Bug 730289 - Filepicker on Android should allow picking or capturing media instead of having a specific button for capture. r=dougt,wesj ui-r=madhava
This commit is contained in:
Родитель
74b8e96361
Коммит
d3bf455beb
|
@ -1105,9 +1105,13 @@ public class GeckoAppShell
|
|||
GeckoApp.mAppContext.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_USER);
|
||||
}
|
||||
|
||||
public static String showFilePicker(String aFilters) {
|
||||
public static String showFilePickerForExtensions(String aExtensions) {
|
||||
return GeckoApp.mAppContext.
|
||||
showFilePicker(getMimeTypeFromExtensions(aFilters));
|
||||
showFilePicker(getMimeTypeFromExtensions(aExtensions));
|
||||
}
|
||||
|
||||
public static String showFilePickerForMimeType(String aMimeType) {
|
||||
return GeckoApp.mAppContext.showFilePicker(aMimeType);
|
||||
}
|
||||
|
||||
public static void performHapticFeedback(boolean aIsLongPress) {
|
||||
|
|
|
@ -71,6 +71,7 @@ import org.json.*;
|
|||
import android.os.*;
|
||||
import android.app.*;
|
||||
import android.text.*;
|
||||
import android.text.format.Time;
|
||||
import android.view.*;
|
||||
import android.view.inputmethod.*;
|
||||
import android.view.ViewGroup.LayoutParams;
|
||||
|
@ -176,7 +177,8 @@ abstract public class GeckoApp
|
|||
|
||||
private static final int FILE_PICKER_REQUEST = 1;
|
||||
private static final int AWESOMEBAR_REQUEST = 2;
|
||||
private static final int CAMERA_CAPTURE_REQUEST = 3;
|
||||
private static final int CAMERA_IMAGE_CAPTURE_REQUEST = 3;
|
||||
private static final int CAMERA_VIDEO_CAPTURE_REQUEST = 4;
|
||||
|
||||
public static boolean checkLaunchState(LaunchState checkState) {
|
||||
synchronized(sLaunchState) {
|
||||
|
@ -942,9 +944,6 @@ abstract public class GeckoApp
|
|||
final String uri = message.getString("uri");
|
||||
final String title = message.getString("title");
|
||||
handleLoadError(tabId, uri, title);
|
||||
} else if (event.equals("onCameraCapture")) {
|
||||
//GeckoApp.mAppContext.doCameraCapture(message.getString("path"));
|
||||
doCameraCapture();
|
||||
} else if (event.equals("Doorhanger:Add")) {
|
||||
handleDoorHanger(message);
|
||||
} else if (event.equals("Doorhanger:Remove")) {
|
||||
|
@ -2345,24 +2344,168 @@ abstract public class GeckoApp
|
|||
Log.i(LOGTAG, "Profile migration took " + timeDiff + " ms");
|
||||
}
|
||||
|
||||
private SynchronousQueue<String> mFilePickerResult = new SynchronousQueue<String>();
|
||||
public String showFilePicker(String aMimeType) {
|
||||
/**
|
||||
* The FilePickerPromptRunnable has to be called to show an intent-like
|
||||
* context menu UI using the PromptService.
|
||||
*/
|
||||
private class FilePickerPromptRunnable implements Runnable {
|
||||
public FilePickerPromptRunnable(String aTitle, PromptService.PromptListItem[] aItems) {
|
||||
super();
|
||||
mTitle = aTitle;
|
||||
mItems = aItems;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
GeckoAppShell.getPromptService().Show(mTitle, "", null, mItems, false);
|
||||
}
|
||||
|
||||
private String mTitle;
|
||||
private PromptService.PromptListItem[] mItems;
|
||||
}
|
||||
|
||||
private int addIntentActivitiesToList(Intent intent, ArrayList<PromptService.PromptListItem> items, ArrayList<Intent> aIntents) {
|
||||
PackageManager pm = mAppContext.getPackageManager();
|
||||
final List<ResolveInfo> lri =
|
||||
pm.queryIntentActivityOptions(GeckoApp.mAppContext.getComponentName(), null, intent, 0);
|
||||
|
||||
if (lri == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (int i=0; i<lri.size(); i++) {
|
||||
final ResolveInfo ri = lri.get(i);
|
||||
Intent rintent = new Intent(intent);
|
||||
rintent.setComponent(new ComponentName(
|
||||
ri.activityInfo.applicationInfo.packageName,
|
||||
ri.activityInfo.name));
|
||||
|
||||
PromptService.PromptListItem item = new PromptService.PromptListItem(ri.loadLabel(pm).toString());
|
||||
item.icon = ri.loadIcon(pm);
|
||||
items.add(item);
|
||||
aIntents.add(rintent);
|
||||
}
|
||||
|
||||
return lri.size();
|
||||
}
|
||||
|
||||
private int AddFilePickingActivities(ArrayList<PromptService.PromptListItem> aItems, String aType, ArrayList<Intent> aIntents) {
|
||||
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
|
||||
intent.setType(aType);
|
||||
intent.addCategory(Intent.CATEGORY_OPENABLE);
|
||||
intent.setType(aMimeType);
|
||||
GeckoApp.this.
|
||||
startActivityForResult(
|
||||
Intent.createChooser(intent, getString(R.string.choose_file)),
|
||||
FILE_PICKER_REQUEST);
|
||||
|
||||
return addIntentActivitiesToList(intent, aItems, aIntents);
|
||||
}
|
||||
|
||||
static private String generateImageName() {
|
||||
Time now = new Time();
|
||||
now.setToNow();
|
||||
return now.format("%Y-%m-%d %H.%M.%S") + ".jpg";
|
||||
}
|
||||
|
||||
private PromptService.PromptListItem[] getItemsAndIntentsForFilePicker(String aMimeType, ArrayList<Intent> aIntents) {
|
||||
ArrayList<PromptService.PromptListItem> items = new ArrayList<PromptService.PromptListItem>();
|
||||
|
||||
if (aMimeType.equals("audio/*")) {
|
||||
if (AddFilePickingActivities(items, "audio/*", aIntents) <= 0) {
|
||||
AddFilePickingActivities(items, "*/*", aIntents);
|
||||
}
|
||||
} else if (aMimeType.equals("image/*")) {
|
||||
mImageFilePath = generateImageName();
|
||||
Intent intent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
|
||||
intent.putExtra(MediaStore.EXTRA_OUTPUT,
|
||||
Uri.fromFile(new File(Environment.getExternalStorageDirectory(),
|
||||
mImageFilePath)));
|
||||
addIntentActivitiesToList(intent, items, aIntents);
|
||||
|
||||
if (AddFilePickingActivities(items, "image/*", aIntents) <= 0) {
|
||||
AddFilePickingActivities(items, "*/*", aIntents);
|
||||
}
|
||||
} else if (aMimeType.equals("video/*")) {
|
||||
Intent intent = new Intent(android.provider.MediaStore.ACTION_VIDEO_CAPTURE);
|
||||
addIntentActivitiesToList(intent, items, aIntents);
|
||||
|
||||
if (AddFilePickingActivities(items, "video/*", aIntents) <= 0) {
|
||||
AddFilePickingActivities(items, "*/*", aIntents);
|
||||
}
|
||||
} else {
|
||||
mImageFilePath = generateImageName();
|
||||
Intent intent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
|
||||
intent.putExtra(MediaStore.EXTRA_OUTPUT,
|
||||
Uri.fromFile(new File(Environment.getExternalStorageDirectory(),
|
||||
mImageFilePath)));
|
||||
addIntentActivitiesToList(intent, items, aIntents);
|
||||
|
||||
intent = new Intent(android.provider.MediaStore.ACTION_VIDEO_CAPTURE);
|
||||
addIntentActivitiesToList(intent, items, aIntents);
|
||||
|
||||
AddFilePickingActivities(items, "*/*", aIntents);
|
||||
}
|
||||
|
||||
return items.toArray(new PromptService.PromptListItem[] {});
|
||||
}
|
||||
|
||||
private String getFilePickerTitle(String aMimeType) {
|
||||
if (aMimeType.equals("audio/*")) {
|
||||
return getString(R.string.filepicker_audio_title);
|
||||
} else if (aMimeType.equals("image/*")) {
|
||||
return getString(R.string.filepicker_image_title);
|
||||
} else if (aMimeType.equals("video/*")) {
|
||||
return getString(R.string.filepicker_video_title);
|
||||
} else {
|
||||
return getString(R.string.filepicker_title);
|
||||
}
|
||||
}
|
||||
|
||||
private String mImageFilePath = "";
|
||||
private SynchronousQueue<String> mFilePickerResult = new SynchronousQueue<String>();
|
||||
|
||||
public String showFilePicker(String aMimeType) {
|
||||
ArrayList<Intent> intents = new ArrayList<Intent>();
|
||||
PromptService.PromptListItem[] items = getItemsAndIntentsForFilePicker(aMimeType, intents);
|
||||
|
||||
GeckoAppShell.getHandler().post(new FilePickerPromptRunnable(getFilePickerTitle(aMimeType), items));
|
||||
|
||||
String promptServiceResult = "";
|
||||
try {
|
||||
promptServiceResult = PromptService.waitForReturn();
|
||||
} catch (InterruptedException e) {
|
||||
Log.e(LOGTAG, "showing prompt failed: ", e);
|
||||
return "";
|
||||
}
|
||||
|
||||
int itemId = -1;
|
||||
try {
|
||||
itemId = new JSONObject(promptServiceResult).getInt("button");
|
||||
|
||||
if (itemId == -1) {
|
||||
return "";
|
||||
}
|
||||
} catch (org.json.JSONException e) {
|
||||
Log.e(LOGTAG, "result from promptservice was invalid: ", e);
|
||||
return "";
|
||||
}
|
||||
|
||||
Intent intent = intents.get(itemId);
|
||||
|
||||
if (intent.getAction().equals(android.provider.MediaStore.ACTION_IMAGE_CAPTURE)) {
|
||||
startActivityForResult(intent, CAMERA_IMAGE_CAPTURE_REQUEST);
|
||||
} else if (intent.getAction().equals(android.provider.MediaStore.ACTION_VIDEO_CAPTURE)) {
|
||||
startActivityForResult(intent, CAMERA_VIDEO_CAPTURE_REQUEST);
|
||||
} else if (intent.getAction().equals(Intent.ACTION_GET_CONTENT)) {
|
||||
startActivityForResult(intent, FILE_PICKER_REQUEST);
|
||||
} else {
|
||||
Log.e(LOGTAG, "We should not get an intent with another action!");
|
||||
return "";
|
||||
}
|
||||
|
||||
String filePickerResult = "";
|
||||
|
||||
try {
|
||||
while (null == (filePickerResult = mFilePickerResult.poll(1, TimeUnit.MILLISECONDS))) {
|
||||
Log.i(LOGTAG, "processing events from showFilePicker ");
|
||||
GeckoAppShell.processNextNativeEvent();
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
Log.i(LOGTAG, "showing file picker ", e);
|
||||
Log.e(LOGTAG, "showing file picker failed: ", e);
|
||||
}
|
||||
|
||||
return filePickerResult;
|
||||
|
@ -2530,27 +2673,43 @@ abstract public class GeckoApp
|
|||
loadRequest(url, type, searchEngine, userEntered);
|
||||
}
|
||||
break;
|
||||
case CAMERA_CAPTURE_REQUEST:
|
||||
Log.i(LOGTAG, "Returning from CAMERA_CAPTURE_REQUEST: " + resultCode);
|
||||
File file = new File(Environment.getExternalStorageDirectory(), "cameraCapture-" + Integer.toString(kCaptureIndex) + ".jpg");
|
||||
kCaptureIndex++;
|
||||
GeckoEvent e = GeckoEvent.createBroadcastEvent("cameraCaptureDone", resultCode == Activity.RESULT_OK ?
|
||||
"{\"ok\": true, \"path\": \"" + file.getPath() + "\" }" :
|
||||
"{\"ok\": false, \"path\": \"" + file.getPath() + "\" }");
|
||||
GeckoAppShell.sendEventToGecko(e);
|
||||
case CAMERA_IMAGE_CAPTURE_REQUEST:
|
||||
try {
|
||||
if (resultCode != Activity.RESULT_OK) {
|
||||
mFilePickerResult.put("");
|
||||
break;
|
||||
}
|
||||
|
||||
File file = new File(Environment.getExternalStorageDirectory(), mImageFilePath);
|
||||
mImageFilePath = "";
|
||||
mFilePickerResult.put(file.getAbsolutePath());
|
||||
} catch (InterruptedException e) {
|
||||
Log.i(LOGTAG, "error returning file picker result", e);
|
||||
}
|
||||
|
||||
break;
|
||||
case CAMERA_VIDEO_CAPTURE_REQUEST:
|
||||
try {
|
||||
if (data == null || resultCode != Activity.RESULT_OK) {
|
||||
mFilePickerResult.put("");
|
||||
break;
|
||||
}
|
||||
|
||||
Cursor cursor = managedQuery(data.getData(),
|
||||
new String[] { MediaStore.Video.Media.DATA },
|
||||
null,
|
||||
null,
|
||||
null);
|
||||
cursor.moveToFirst();
|
||||
mFilePickerResult.put(cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DATA)));
|
||||
} catch (InterruptedException e) {
|
||||
Log.i(LOGTAG, "error returning file picker result", e);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void doCameraCapture() {
|
||||
File file = new File(Environment.getExternalStorageDirectory(), "cameraCapture-" + Integer.toString(kCaptureIndex) + ".jpg");
|
||||
|
||||
Intent intent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
|
||||
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(file));
|
||||
|
||||
startActivityForResult(intent, CAMERA_CAPTURE_REQUEST);
|
||||
}
|
||||
|
||||
// If searchEngine is provided, url will be used as the search query.
|
||||
// Otherwise, the url is loaded.
|
||||
private void loadRequest(String url, AwesomeBar.Type type, String searchEngine, boolean userEntered) {
|
||||
|
|
|
@ -1090,9 +1090,13 @@ public class GeckoAppShell
|
|||
GeckoApp.mAppContext.setFullScreen(fullscreen);
|
||||
}
|
||||
|
||||
public static String showFilePicker(String aFilters) {
|
||||
public static String showFilePickerForExtensions(String aExtensions) {
|
||||
return GeckoApp.mAppContext.
|
||||
showFilePicker(getMimeTypeFromExtensions(aFilters));
|
||||
showFilePicker(getMimeTypeFromExtensions(aExtensions));
|
||||
}
|
||||
|
||||
public static String showFilePickerForMimeType(String aMimeType) {
|
||||
return GeckoApp.mAppContext.showFilePicker(aMimeType);
|
||||
}
|
||||
|
||||
public static void performHapticFeedback(boolean aIsLongPress) {
|
||||
|
@ -1617,8 +1621,6 @@ public class GeckoAppShell
|
|||
}
|
||||
}
|
||||
|
||||
static SynchronousQueue<String> sPromptQueue = null;
|
||||
|
||||
public static void registerGeckoEventListener(String event, GeckoEventListener listener) {
|
||||
if (mEventListeners == null)
|
||||
mEventListeners = new HashMap<String, ArrayList<GeckoEventListener>>();
|
||||
|
@ -1678,8 +1680,6 @@ public class GeckoAppShell
|
|||
String type = geckoObject.getString("type");
|
||||
|
||||
if (type.equals("Prompt:Show")) {
|
||||
if (sPromptQueue == null)
|
||||
sPromptQueue = new SynchronousQueue<String>();
|
||||
getHandler().post(new Runnable() {
|
||||
public void run() {
|
||||
getPromptService().processMessage(geckoObject);
|
||||
|
@ -1688,9 +1688,7 @@ public class GeckoAppShell
|
|||
|
||||
String promptServiceResult = "";
|
||||
try {
|
||||
while (null == (promptServiceResult = sPromptQueue.poll(1, TimeUnit.MILLISECONDS))) {
|
||||
processNextNativeEvent();
|
||||
}
|
||||
promptServiceResult = PromptService.waitForReturn();
|
||||
} catch (InterruptedException e) {
|
||||
Log.i(LOGTAG, "showing prompt ", e);
|
||||
}
|
||||
|
|
|
@ -112,7 +112,7 @@ public class GeckoScreenOrientationListener
|
|||
}
|
||||
|
||||
if (mShouldNotify && mOrientation != previousOrientation) {
|
||||
GeckoAppShell.sendEventToGecko(new GeckoEvent(mOrientation));
|
||||
GeckoAppShell.sendEventToGecko(GeckoEvent.createScreenOrientationEvent(mOrientation));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -39,6 +39,8 @@ package org.mozilla.gecko;
|
|||
|
||||
import android.util.Log;
|
||||
import java.lang.String;
|
||||
import java.util.concurrent.SynchronousQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import android.app.AlertDialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
|
@ -46,7 +48,10 @@ import android.content.DialogInterface.OnClickListener;
|
|||
import android.content.DialogInterface.OnCancelListener;
|
||||
import android.content.DialogInterface.OnMultiChoiceClickListener;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.text.InputType;
|
||||
import android.text.method.PasswordTransformationMethod;
|
||||
import android.util.TypedValue;
|
||||
|
@ -74,15 +79,40 @@ public class PromptService implements OnClickListener, OnCancelListener, OnItemC
|
|||
private PromptInput[] mInputs;
|
||||
private AlertDialog mDialog = null;
|
||||
private static LayoutInflater mInflater;
|
||||
private final static int PADDING_SIZE = 32; // in dip units
|
||||
private static int mPaddingSize = 0; // calculated from PADDING_SIZE. In pixel units
|
||||
|
||||
private final static int GROUP_PADDING_SIZE = 32; // in dip units
|
||||
private static int mGroupPaddingSize = 0; // calculated from GROUP_PADDING_SIZE. In pixel units
|
||||
|
||||
private final static int LEFT_RIGHT_TEXT_WITH_ICON_PADDING = 10; // in dip units
|
||||
private static int mLeftRightTextWithIconPadding = 0; // calculated from LEFT_RIGHT_TEXT_WITH_ICON_PADDING.
|
||||
|
||||
private final static int TOP_BOTTOM_TEXT_WITH_ICON_PADDING = 8; // in dip units
|
||||
private static int mTopBottomTextWithIconPadding = 0; // calculated from TOP_BOTTOM_TEXT_WITH_ICON_PADDING.
|
||||
|
||||
private final static int ICON_TEXT_PADDING = 10; // in dip units
|
||||
private static int mIconTextPadding = 0; // calculated from ICON_TEXT_PADDING.
|
||||
|
||||
private final static int ICON_SIZE = 72; // in dip units
|
||||
private static int mIconSize = 0; // calculated from ICON_SIZE.
|
||||
|
||||
PromptService() {
|
||||
mInflater = LayoutInflater.from(GeckoApp.mAppContext);
|
||||
Resources res = GeckoApp.mAppContext.getResources();
|
||||
mPaddingSize = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
|
||||
PADDING_SIZE,
|
||||
res.getDisplayMetrics());
|
||||
mGroupPaddingSize = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
|
||||
GROUP_PADDING_SIZE,
|
||||
res.getDisplayMetrics());
|
||||
mLeftRightTextWithIconPadding = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
|
||||
LEFT_RIGHT_TEXT_WITH_ICON_PADDING,
|
||||
res.getDisplayMetrics());
|
||||
mTopBottomTextWithIconPadding = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
|
||||
TOP_BOTTOM_TEXT_WITH_ICON_PADDING,
|
||||
res.getDisplayMetrics());
|
||||
mIconTextPadding = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
|
||||
ICON_TEXT_PADDING,
|
||||
res.getDisplayMetrics());
|
||||
mIconSize = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
|
||||
ICON_SIZE,
|
||||
res.getDisplayMetrics());
|
||||
}
|
||||
|
||||
private class PromptButton {
|
||||
|
@ -184,8 +214,8 @@ public class PromptService implements OnClickListener, OnCancelListener, OnItemC
|
|||
builder.setMessage(aText);
|
||||
}
|
||||
|
||||
int length = mInputs.length;
|
||||
if (aMenuList.length > 0) {
|
||||
int length = mInputs == null ? 0 : mInputs.length;
|
||||
if (aMenuList != null && aMenuList.length > 0) {
|
||||
int resourceId = android.R.layout.select_dialog_item;
|
||||
if (mSelected != null && mSelected.length > 0) {
|
||||
if (aMultipleSelection) {
|
||||
|
@ -230,7 +260,7 @@ public class PromptService implements OnClickListener, OnCancelListener, OnItemC
|
|||
builder.setView((View)linearLayout);
|
||||
}
|
||||
|
||||
length = aButtons.length;
|
||||
length = aButtons == null ? 0 : aButtons.length;
|
||||
if (length > 0) {
|
||||
builder.setPositiveButton(aButtons[0].label, this);
|
||||
}
|
||||
|
@ -299,12 +329,24 @@ public class PromptService implements OnClickListener, OnCancelListener, OnItemC
|
|||
finishDialog(ret.toString());
|
||||
}
|
||||
|
||||
static SynchronousQueue<String> mPromptQueue = new SynchronousQueue<String>();
|
||||
|
||||
static public String waitForReturn() throws InterruptedException {
|
||||
String value;
|
||||
|
||||
while (null == (value = mPromptQueue.poll(1, TimeUnit.MILLISECONDS))) {
|
||||
GeckoAppShell.processNextNativeEvent();
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public void finishDialog(String aReturn) {
|
||||
mInputs = null;
|
||||
mDialog = null;
|
||||
mSelected = null;
|
||||
try {
|
||||
GeckoAppShell.sPromptQueue.put(aReturn);
|
||||
mPromptQueue.put(aReturn);
|
||||
} catch(Exception ex) { }
|
||||
}
|
||||
|
||||
|
@ -396,12 +438,16 @@ public class PromptService implements OnClickListener, OnCancelListener, OnItemC
|
|||
return list;
|
||||
}
|
||||
|
||||
private class PromptListItem {
|
||||
static public class PromptListItem {
|
||||
public String label = "";
|
||||
public boolean isGroup = false;
|
||||
public boolean inGroup = false;
|
||||
public boolean disabled = false;
|
||||
public int id = 0;
|
||||
|
||||
// This member can't be accessible from JS, see bug 733749.
|
||||
public Drawable icon = null;
|
||||
|
||||
PromptListItem(JSONObject aObject) {
|
||||
try { label = aObject.getString("label"); } catch(Exception ex) { }
|
||||
try { isGroup = aObject.getBoolean("isGroup"); } catch(Exception ex) { }
|
||||
|
@ -409,6 +455,10 @@ public class PromptService implements OnClickListener, OnCancelListener, OnItemC
|
|||
try { disabled = aObject.getBoolean("disabled"); } catch(Exception ex) { }
|
||||
try { id = aObject.getInt("id"); } catch(Exception ex) { }
|
||||
}
|
||||
|
||||
public PromptListItem(String aLabel) {
|
||||
label = aLabel;
|
||||
}
|
||||
}
|
||||
|
||||
public class PromptListAdapter extends ArrayAdapter<PromptListItem> {
|
||||
|
@ -455,15 +505,34 @@ public class PromptService implements OnClickListener, OnCancelListener, OnItemC
|
|||
}
|
||||
|
||||
if (item.inGroup) {
|
||||
ct.setPadding(mPaddingSize, 0, 0, 0);
|
||||
ct.setPadding(mGroupPaddingSize, 0, 0, 0);
|
||||
}
|
||||
|
||||
}
|
||||
} catch (Exception ex) { }
|
||||
}
|
||||
|
||||
TextView t1 = (TextView) row.findViewById(android.R.id.text1);
|
||||
if (t1 != null) {
|
||||
t1.setText(item.label);
|
||||
if (item.icon != null) {
|
||||
Resources res = GeckoApp.mAppContext.getResources();
|
||||
|
||||
// Set padding inside the item.
|
||||
t1.setPadding(item. inGroup ? mLeftRightTextWithIconPadding + mGroupPaddingSize : mLeftRightTextWithIconPadding,
|
||||
mTopBottomTextWithIconPadding,
|
||||
mLeftRightTextWithIconPadding, mTopBottomTextWithIconPadding);
|
||||
|
||||
// Set the padding between the icon and the text.
|
||||
t1.setCompoundDrawablePadding(mIconTextPadding);
|
||||
|
||||
// We want the icon to be of a specific size. Some do not
|
||||
// follow this rule so we have to resize them.
|
||||
Bitmap bitmap = ((BitmapDrawable) item.icon).getBitmap();
|
||||
Drawable d = new BitmapDrawable(Bitmap.createScaledBitmap(bitmap, mIconSize, mIconSize, true));
|
||||
|
||||
t1.setCompoundDrawablesWithIntrinsicBounds(d, null, null, null);
|
||||
}
|
||||
}
|
||||
|
||||
return row;
|
||||
|
|
|
@ -119,3 +119,8 @@
|
|||
<!ENTITY abouthome_no_top_sites "You do not have any top sites yet. Tap the Title Bar to start browsing.">
|
||||
<!ENTITY abouthome_about_sync "Set up Firefox Sync to access bookmarks, history and tabs from your other devices">
|
||||
<!ENTITY abouthome_sync_bold_name "Firefox Sync">
|
||||
|
||||
<!ENTITY filepicker_title "Choose File">
|
||||
<!ENTITY filepicker_audio_title "Choose or record a sound">
|
||||
<!ENTITY filepicker_image_title "Choose or take a picture">
|
||||
<!ENTITY filepicker_video_title "Choose or record a video">
|
||||
|
|
|
@ -123,4 +123,9 @@
|
|||
<string name="abouthome_no_top_sites">&abouthome_no_top_sites;</string>
|
||||
<string name="abouthome_about_sync">&abouthome_about_sync;</string>
|
||||
<string name="abouthome_sync_bold_name">&abouthome_sync_bold_name;</string>
|
||||
|
||||
<string name="filepicker_title">&filepicker_title;</string>
|
||||
<string name="filepicker_audio_title">&filepicker_audio_title;</string>
|
||||
<string name="filepicker_image_title">&filepicker_image_title;</string>
|
||||
<string name="filepicker_video_title">&filepicker_video_title;</string>
|
||||
</resources>
|
||||
|
|
|
@ -1,140 +0,0 @@
|
|||
/* -*- Mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil; -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is CapturePicker.js
|
||||
*
|
||||
* The Initial Developer of the Original Code is Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Kyle Huey <me@kylehuey.com>
|
||||
* Fabrice Desré <fabrice@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cr = Components.results;
|
||||
const Cu = Components.utils;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
function CapturePicker() {
|
||||
|
||||
}
|
||||
|
||||
CapturePicker.prototype = {
|
||||
_file: null,
|
||||
_mode: -1,
|
||||
_result: -1,
|
||||
_shown: false,
|
||||
_title: "",
|
||||
_type: "",
|
||||
_window: null,
|
||||
_done: null,
|
||||
|
||||
//
|
||||
// nsICapturePicker
|
||||
//
|
||||
init: function(aWindow, aTitle, aMode) {
|
||||
this._window = aWindow;
|
||||
this._title = aTitle;
|
||||
this._mode = aMode;
|
||||
},
|
||||
|
||||
show: function() {
|
||||
if (this._shown)
|
||||
throw Cr.NS_ERROR_UNEXPECTED;
|
||||
|
||||
this._shown = true;
|
||||
this._file = null;
|
||||
this._done = false;
|
||||
|
||||
Services.obs.addObserver(this, "cameraCaptureDone", false);
|
||||
|
||||
let msg = { gecko: { type: "onCameraCapture" } };
|
||||
Cc["@mozilla.org/android/bridge;1"].getService(Ci.nsIAndroidBridge).handleGeckoMessage(JSON.stringify(msg));
|
||||
|
||||
// we need to turn all the async messaging into a blocking call
|
||||
while (!this._done)
|
||||
Services.tm.currentThread.processNextEvent(true);
|
||||
|
||||
if (this._res.ok) {
|
||||
this._file = this._res.path;
|
||||
// delete the file when exiting
|
||||
let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
|
||||
file.initWithPath(this._res.path);
|
||||
Cc["@mozilla.org/uriloader/external-helper-app-service;1"].getService(Ci.nsPIExternalAppLauncher).deleteTemporaryFileOnExit(file);
|
||||
}
|
||||
|
||||
return (this._res.ok ? Ci.nsICapturePicker.RETURN_OK : Ci.nsICapturePicker.RETURN_CANCEL);
|
||||
},
|
||||
|
||||
observe: function(aObject, aTopic, aData) {
|
||||
Services.obs.removeObserver(this, "cameraCaptureDone");
|
||||
this._done = true;
|
||||
this._res = JSON.parse(aData);
|
||||
},
|
||||
|
||||
modeMayBeAvailable: function(aMode) {
|
||||
if (aMode != Ci.nsICapturePicker.MODE_STILL)
|
||||
return false;
|
||||
return true;
|
||||
},
|
||||
|
||||
get file() {
|
||||
if (this._file) {
|
||||
let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
|
||||
file.initWithPath(this._file);
|
||||
let utils = this._window.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
|
||||
return utils.wrapDOMFile(file);
|
||||
} else {
|
||||
throw Cr.NS_ERROR_FAILURE;
|
||||
}
|
||||
},
|
||||
|
||||
get type() {
|
||||
return this._type;
|
||||
},
|
||||
|
||||
set type(aNewType) {
|
||||
if (this._shown)
|
||||
throw Cr.NS_ERROR_UNEXPECTED;
|
||||
else
|
||||
this._type = aNewType;
|
||||
},
|
||||
|
||||
// QI
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsICapturePicker, Ci.nsIObserver]),
|
||||
|
||||
// XPCOMUtils factory
|
||||
classID: Components.ID("{cb5a47f0-b58c-4fc3-b61a-358ee95f8238}"),
|
||||
};
|
||||
|
||||
var components = [ CapturePicker ];
|
||||
const NSGetFactory = XPCOMUtils.generateNSGetFactory(components);
|
|
@ -71,7 +71,6 @@ EXTRA_COMPONENTS = \
|
|||
FormAutoComplete.js \
|
||||
LoginManagerPrompter.js \
|
||||
BlocklistPrompt.js \
|
||||
CapturePicker.js \
|
||||
$(NULL)
|
||||
|
||||
ifdef MOZ_SAFE_BROWSING
|
||||
|
|
|
@ -102,7 +102,3 @@ component {88b3eb21-d072-4e3b-886d-f89d8c49fe59} UpdatePrompt.js
|
|||
contract @mozilla.org/updates/update-prompt;1 {88b3eb21-d072-4e3b-886d-f89d8c49fe59}
|
||||
#endif
|
||||
|
||||
# CapturePicker.js
|
||||
component {cb5a47f0-b58c-4fc3-b61a-358ee95f8238} CapturePicker.js
|
||||
contract @mozilla.org/capturepicker;1 {cb5a47f0-b58c-4fc3-b61a-358ee95f8238}
|
||||
|
||||
|
|
|
@ -131,7 +131,8 @@ AndroidBridge::Init(JNIEnv *jEnv,
|
|||
jGetClipboardText = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "getClipboardText", "()Ljava/lang/String;");
|
||||
jSetClipboardText = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "setClipboardText", "(Ljava/lang/String;)V");
|
||||
jShowAlertNotification = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "showAlertNotification", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
|
||||
jShowFilePicker = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "showFilePicker", "(Ljava/lang/String;)Ljava/lang/String;");
|
||||
jShowFilePickerForExtensions = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "showFilePickerForExtensions", "(Ljava/lang/String;)Ljava/lang/String;");
|
||||
jShowFilePickerForMimeType = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "showFilePickerForMimeType", "(Ljava/lang/String;)Ljava/lang/String;");
|
||||
jAlertsProgressListener_OnProgress = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "alertsProgressListener_OnProgress", "(Ljava/lang/String;JJLjava/lang/String;)V");
|
||||
jAlertsProgressListener_OnCancel = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "alertsProgressListener_OnCancel", "(Ljava/lang/String;)V");
|
||||
jGetDpi = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "getDpi", "()I");
|
||||
|
@ -742,20 +743,38 @@ AndroidBridge::GetDPI()
|
|||
}
|
||||
|
||||
void
|
||||
AndroidBridge::ShowFilePicker(nsAString& aFilePath, nsAString& aFilters)
|
||||
AndroidBridge::ShowFilePickerForExtensions(nsAString& aFilePath, const nsAString& aExtensions)
|
||||
{
|
||||
ALOG_BRIDGE("AndroidBridge::ShowFilePicker");
|
||||
ALOG_BRIDGE("AndroidBridge::ShowFilePickerForExtensions");
|
||||
|
||||
JNIEnv *env = GetJNIEnv();
|
||||
if (!env)
|
||||
return;
|
||||
|
||||
AutoLocalJNIFrame jniFrame(env);
|
||||
jstring jstrFilers = env->NewString(nsPromiseFlatString(aFilters).get(),
|
||||
aFilters.Length());
|
||||
jstring jstrFilers = env->NewString(nsPromiseFlatString(aExtensions).get(),
|
||||
aExtensions.Length());
|
||||
jstring jstr = static_cast<jstring>(env->CallStaticObjectMethod(
|
||||
mGeckoAppShellClass,
|
||||
jShowFilePickerForExtensions, jstrFilers));
|
||||
aFilePath.Assign(nsJNIString(jstr));
|
||||
}
|
||||
|
||||
void
|
||||
AndroidBridge::ShowFilePickerForMimeType(nsAString& aFilePath, const nsAString& aMimeType)
|
||||
{
|
||||
ALOG_BRIDGE("AndroidBridge::ShowFilePickerForMimeType");
|
||||
|
||||
JNIEnv *env = GetJNIEnv();
|
||||
if (!env)
|
||||
return;
|
||||
|
||||
AutoLocalJNIFrame jniFrame(env);
|
||||
jstring jstrFilers = env->NewString(nsPromiseFlatString(aMimeType).get(),
|
||||
aMimeType.Length());
|
||||
jstring jstr = static_cast<jstring>(env->CallStaticObjectMethod(
|
||||
mGeckoAppShellClass,
|
||||
jShowFilePicker, jstrFilers));
|
||||
jShowFilePickerForMimeType, jstrFilers));
|
||||
aFilePath.Assign(nsJNIString(jstr));
|
||||
}
|
||||
|
||||
|
|
|
@ -241,7 +241,8 @@ public:
|
|||
|
||||
int GetDPI();
|
||||
|
||||
void ShowFilePicker(nsAString& aFilePath, nsAString& aFilters);
|
||||
void ShowFilePickerForExtensions(nsAString& aFilePath, const nsAString& aExtensions);
|
||||
void ShowFilePickerForMimeType(nsAString& aFilePath, const nsAString& aMimeType);
|
||||
|
||||
void PerformHapticFeedback(bool aIsLongPress);
|
||||
|
||||
|
@ -478,7 +479,8 @@ protected:
|
|||
jmethodID jGetClipboardText;
|
||||
jmethodID jSetClipboardText;
|
||||
jmethodID jShowAlertNotification;
|
||||
jmethodID jShowFilePicker;
|
||||
jmethodID jShowFilePickerForExtensions;
|
||||
jmethodID jShowFilePickerForMimeType;
|
||||
jmethodID jAlertsProgressListener_OnProgress;
|
||||
jmethodID jAlertsProgressListener_OnCancel;
|
||||
jmethodID jGetDpi;
|
||||
|
|
|
@ -51,12 +51,37 @@ NS_IMETHODIMP nsFilePicker::Init(nsIDOMWindow *parent, const nsAString& title,
|
|||
: NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsFilePicker::AppendFilters(PRInt32 aFilterMask)
|
||||
{
|
||||
if (aFilterMask == (filterAudio | filterAll)) {
|
||||
mMimeTypeFilter.AssignLiteral("audio/*");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (aFilterMask == (filterImages | filterAll)) {
|
||||
mMimeTypeFilter.AssignLiteral("image/*");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (aFilterMask == (filterVideo | filterAll)) {
|
||||
mMimeTypeFilter.AssignLiteral("video/*");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (aFilterMask & filterAll) {
|
||||
mMimeTypeFilter.AssignLiteral("*/*");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return nsBaseFilePicker::AppendFilters(aFilterMask);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsFilePicker::AppendFilter(const nsAString& /*title*/,
|
||||
const nsAString& filter)
|
||||
{
|
||||
if (!mFilters.IsEmpty())
|
||||
mFilters.AppendLiteral(", ");
|
||||
mFilters.Append(filter);
|
||||
if (!mExtensionsFilter.IsEmpty())
|
||||
mExtensionsFilter.AppendLiteral(", ");
|
||||
mExtensionsFilter.Append(filter);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -126,7 +151,15 @@ NS_IMETHODIMP nsFilePicker::Show(PRInt16 *_retval NS_OUTPARAM)
|
|||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
nsAutoString filePath;
|
||||
|
||||
mozilla::AndroidBridge::Bridge()->ShowFilePicker(filePath, mFilters);
|
||||
if (mExtensionsFilter.IsEmpty() == mMimeTypeFilter.IsEmpty()) {
|
||||
// Both filters or none of them are set. We want to show anything we can.
|
||||
mozilla::AndroidBridge::Bridge()->ShowFilePickerForMimeType(filePath, NS_LITERAL_STRING("*/*"));
|
||||
} else if (!mExtensionsFilter.IsEmpty()) {
|
||||
mozilla::AndroidBridge::Bridge()->ShowFilePickerForExtensions(filePath, mExtensionsFilter);
|
||||
} else {
|
||||
mozilla::AndroidBridge::Bridge()->ShowFilePickerForMimeType(filePath, mMimeTypeFilter);
|
||||
}
|
||||
|
||||
*_retval = EmptyString().Equals(filePath) ?
|
||||
nsIFilePicker::returnCancel : nsIFilePicker::returnOK;
|
||||
if (*_retval == nsIFilePicker::returnOK)
|
||||
|
|
|
@ -48,6 +48,7 @@ public:
|
|||
|
||||
NS_IMETHODIMP Init(nsIDOMWindow *parent, const nsAString& title,
|
||||
PRInt16 mode);
|
||||
NS_IMETHOD AppendFilters(PRInt32 aFilterMask);
|
||||
NS_IMETHOD AppendFilter(const nsAString & aTitle,
|
||||
const nsAString & aFilter);
|
||||
NS_IMETHOD GetDefaultString(nsAString & aDefaultString);
|
||||
|
@ -62,6 +63,7 @@ public:
|
|||
private:
|
||||
void InitNative(nsIWidget*, const nsAString&, PRInt16) {};
|
||||
nsString mFilePath;
|
||||
nsString mFilters;
|
||||
nsString mExtensionsFilter;
|
||||
nsString mMimeTypeFilter;
|
||||
};
|
||||
#endif
|
||||
|
|
Загрузка…
Ссылка в новой задаче