зеркало из https://github.com/mozilla/gecko-dev.git
Bug 942270 - Support quickshare in context menus. r=bnicholson
This commit is contained in:
Родитель
43735732bb
Коммит
1d56b0fe1e
|
@ -640,10 +640,6 @@ public abstract class GeckoApp
|
|||
} else if (event.equals("Share:Text")) {
|
||||
String text = message.getString("text");
|
||||
GeckoAppShell.openUriExternal(text, "text/plain", "", "", Intent.ACTION_SEND, "");
|
||||
} else if (event.equals("Share:Image")) {
|
||||
String src = message.getString("url");
|
||||
String type = message.getString("mime");
|
||||
GeckoAppShell.shareImage(src, type);
|
||||
} else if (event.equals("Image:SetAs")) {
|
||||
String src = message.getString("url");
|
||||
setImageAs(src);
|
||||
|
@ -1585,7 +1581,6 @@ public abstract class GeckoApp
|
|||
registerEventListener("Accessibility:Ready");
|
||||
registerEventListener("Shortcut:Remove");
|
||||
registerEventListener("Share:Text");
|
||||
registerEventListener("Share:Image");
|
||||
registerEventListener("Image:SetAs");
|
||||
registerEventListener("Sanitize:ClearHistory");
|
||||
registerEventListener("Update:Check");
|
||||
|
@ -2119,7 +2114,6 @@ public abstract class GeckoApp
|
|||
unregisterEventListener("Accessibility:Ready");
|
||||
unregisterEventListener("Shortcut:Remove");
|
||||
unregisterEventListener("Share:Text");
|
||||
unregisterEventListener("Share:Image");
|
||||
unregisterEventListener("Image:SetAs");
|
||||
unregisterEventListener("Sanitize:ClearHistory");
|
||||
unregisterEventListener("Update:Check");
|
||||
|
|
|
@ -1048,81 +1048,6 @@ public class GeckoAppShell
|
|||
} catch (IOException e) {}
|
||||
}
|
||||
|
||||
static void shareImage(String aSrc, String aType) {
|
||||
|
||||
Intent intent = new Intent(Intent.ACTION_SEND);
|
||||
boolean isDataURI = aSrc.startsWith("data:");
|
||||
OutputStream os = null;
|
||||
File dir = GeckoApp.getTempDirectory();
|
||||
|
||||
if (dir == null) {
|
||||
showImageShareFailureToast();
|
||||
return;
|
||||
}
|
||||
|
||||
GeckoApp.deleteTempFiles();
|
||||
|
||||
try {
|
||||
// Create a temporary file for the image
|
||||
File imageFile = File.createTempFile("image",
|
||||
"." + aType.replace("image/",""),
|
||||
dir);
|
||||
os = new FileOutputStream(imageFile);
|
||||
|
||||
if (isDataURI) {
|
||||
// We are dealing with a Data URI
|
||||
int dataStart = aSrc.indexOf(',');
|
||||
byte[] buf = Base64.decode(aSrc.substring(dataStart+1), Base64.DEFAULT);
|
||||
os.write(buf);
|
||||
} else {
|
||||
// We are dealing with a URL
|
||||
InputStream is = null;
|
||||
try {
|
||||
URL url = new URL(aSrc);
|
||||
is = url.openStream();
|
||||
byte[] buf = new byte[2048];
|
||||
int length;
|
||||
|
||||
while ((length = is.read(buf)) != -1) {
|
||||
os.write(buf, 0, length);
|
||||
}
|
||||
} finally {
|
||||
safeStreamClose(is);
|
||||
}
|
||||
}
|
||||
intent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(imageFile));
|
||||
|
||||
// If we were able to determine the image type, send that in the intent. Otherwise,
|
||||
// use a generic type.
|
||||
if (aType.startsWith("image/")) {
|
||||
intent.setType(aType);
|
||||
} else {
|
||||
intent.setType("image/*");
|
||||
}
|
||||
} catch (IOException e) {
|
||||
if (!isDataURI) {
|
||||
// If we failed, at least send through the URL link
|
||||
intent.putExtra(Intent.EXTRA_TEXT, aSrc);
|
||||
intent.setType("text/plain");
|
||||
} else {
|
||||
showImageShareFailureToast();
|
||||
return;
|
||||
}
|
||||
} finally {
|
||||
safeStreamClose(os);
|
||||
}
|
||||
getContext().startActivity(Intent.createChooser(intent,
|
||||
getContext().getResources().getString(R.string.share_title)));
|
||||
}
|
||||
|
||||
// Don't fail silently, tell the user that we weren't able to share the image
|
||||
private static final void showImageShareFailureToast() {
|
||||
Toast toast = Toast.makeText(getContext(),
|
||||
getContext().getResources().getString(R.string.share_image_failed),
|
||||
Toast.LENGTH_SHORT);
|
||||
toast.show();
|
||||
}
|
||||
|
||||
static boolean isUriSafeForScheme(Uri aUri) {
|
||||
// Bug 794034 - We don't want to pass MWI or USSD codes to the
|
||||
// dialer, and ensure the Uri class doesn't parse a URI
|
||||
|
|
|
@ -37,11 +37,11 @@ public class PromptListItem {
|
|||
id = aObject.optInt("id");
|
||||
mSelected = aObject.optBoolean("selected");
|
||||
|
||||
JSONObject obj = aObject.optJSONObject("shareData");
|
||||
JSONObject obj = aObject.optJSONObject("showAsActions");
|
||||
if (obj != null) {
|
||||
showAsActions = true;
|
||||
String uri = obj.isNull("uri") ? "" : obj.optString("uri");
|
||||
String type = obj.isNull("type") ? "" : obj.optString("type");
|
||||
String type = obj.isNull("type") ? "text/html" : obj.optString("type", "text/html");
|
||||
mIntent = GeckoAppShell.getShareIntent(GeckoAppShell.getContext(), uri, type, "");
|
||||
isParent = true;
|
||||
} else {
|
||||
|
|
|
@ -18,6 +18,7 @@ import android.view.MenuItem.OnMenuItemClickListener;
|
|||
import android.view.SubMenu;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
|
@ -47,16 +48,40 @@ public class GeckoActionProvider extends ActionProvider {
|
|||
|
||||
private static HashMap<String, GeckoActionProvider> mProviders = new HashMap<String, GeckoActionProvider>();
|
||||
|
||||
private static String getFilenameFromMimeType(String mimeType) {
|
||||
String[] mime = mimeType.split("/");
|
||||
if (mime.length == 1) {
|
||||
return "history-" + mime[0] + ".xml";
|
||||
}
|
||||
|
||||
// Separate out tel and mailto for their own media types
|
||||
if ("text".equals(mime[0])) {
|
||||
if ("tel".equals(mime[1])) {
|
||||
return "history-phone.xml";
|
||||
} else if ("mailto".equals(mime[1])) {
|
||||
return "history-email.xml";
|
||||
} else if ("html".equals(mime[1])) {
|
||||
return DEFAULT_HISTORY_FILE_NAME;
|
||||
}
|
||||
}
|
||||
|
||||
return "history-" + mime[0] + ".xml";
|
||||
}
|
||||
|
||||
// Gets the action provider for a particular mimetype
|
||||
public static GeckoActionProvider getForType(String type, Context context) {
|
||||
if (!mProviders.keySet().contains(type)) {
|
||||
public static GeckoActionProvider getForType(String mimeType, Context context) {
|
||||
if (!mProviders.keySet().contains(mimeType)) {
|
||||
GeckoActionProvider provider = new GeckoActionProvider(context);
|
||||
|
||||
String subType = type.substring(0, type.indexOf("/"));
|
||||
provider.setHistoryFileName("history-" + subType + ".xml");
|
||||
mProviders.put(type, provider);
|
||||
// For empty types, we just return a default provider
|
||||
if (TextUtils.isEmpty(mimeType)) {
|
||||
return provider;
|
||||
}
|
||||
|
||||
provider.setHistoryFileName(getFilenameFromMimeType(mimeType));
|
||||
mProviders.put(mimeType, provider);
|
||||
}
|
||||
return mProviders.get(type);
|
||||
return mProviders.get(mimeType);
|
||||
}
|
||||
|
||||
public GeckoActionProvider(Context context) {
|
||||
|
|
|
@ -508,7 +508,7 @@ var BrowserApp = {
|
|||
NativeWindow.contextmenus.emailLinkContext,
|
||||
function(aTarget) {
|
||||
let url = NativeWindow.contextmenus._getLinkURL(aTarget);
|
||||
let emailAddr = NativeWindow.contextmenus._stripScheme(url);
|
||||
let [,emailAddr] = NativeWindow.contextmenus._stripScheme(url);
|
||||
NativeWindow.contextmenus._copyStringToDefaultClipboard(emailAddr);
|
||||
});
|
||||
|
||||
|
@ -516,35 +516,59 @@ var BrowserApp = {
|
|||
NativeWindow.contextmenus.phoneNumberLinkContext,
|
||||
function(aTarget) {
|
||||
let url = NativeWindow.contextmenus._getLinkURL(aTarget);
|
||||
let phoneNumber = NativeWindow.contextmenus._stripScheme(url);
|
||||
let [,phoneNumber] = NativeWindow.contextmenus._stripScheme(url);
|
||||
NativeWindow.contextmenus._copyStringToDefaultClipboard(phoneNumber);
|
||||
});
|
||||
|
||||
NativeWindow.contextmenus.add(Strings.browser.GetStringFromName("contextmenu.shareLink"),
|
||||
NativeWindow.contextmenus._disableInGuest(NativeWindow.contextmenus.linkShareableContext),
|
||||
function(aTarget) {
|
||||
let url = NativeWindow.contextmenus._getLinkURL(aTarget);
|
||||
let title = aTarget.textContent || aTarget.title;
|
||||
NativeWindow.contextmenus._shareStringWithDefault(url, title);
|
||||
});
|
||||
NativeWindow.contextmenus.add({
|
||||
label: Strings.browser.GetStringFromName("contextmenu.shareLink"),
|
||||
order: NativeWindow.contextmenus.DEFAULT_HTML5_ORDER-1, // Show above HTML5 menu items
|
||||
selector: NativeWindow.contextmenus._disableInGuest(NativeWindow.contextmenus.linkShareableContext),
|
||||
showAsActions: function(aElement) {
|
||||
return {
|
||||
title: aElement.textContent.trim() || aElement.title.trim(),
|
||||
uri: NativeWindow.contextmenus._getLinkURL(aElement),
|
||||
}
|
||||
},
|
||||
icon: "drawable://ic_menu_share",
|
||||
callback: function(aTarget) { }
|
||||
});
|
||||
|
||||
NativeWindow.contextmenus.add(Strings.browser.GetStringFromName("contextmenu.shareEmailAddress"),
|
||||
NativeWindow.contextmenus._disableInGuest(NativeWindow.contextmenus.emailLinkContext),
|
||||
function(aTarget) {
|
||||
let url = NativeWindow.contextmenus._getLinkURL(aTarget);
|
||||
let emailAddr = NativeWindow.contextmenus._stripScheme(url);
|
||||
let title = aTarget.textContent || aTarget.title;
|
||||
NativeWindow.contextmenus._shareStringWithDefault(emailAddr, title);
|
||||
});
|
||||
NativeWindow.contextmenus.add({
|
||||
label: Strings.browser.GetStringFromName("contextmenu.shareEmailAddress"),
|
||||
order: NativeWindow.contextmenus.DEFAULT_HTML5_ORDER - 1,
|
||||
selector: NativeWindow.contextmenus._disableInGuest(NativeWindow.contextmenus.emailLinkContext),
|
||||
showAsActions: function(aElement) {
|
||||
let url = NativeWindow.contextmenus._getLinkURL(aElement);
|
||||
let [, emailAddr] = NativeWindow.contextmenus._stripScheme(url);
|
||||
let title = aElement.textContent || aElement.title;
|
||||
return {
|
||||
title: title,
|
||||
uri: emailAddr,
|
||||
type: "text/mailto",
|
||||
}
|
||||
},
|
||||
icon: "drawable://ic_menu_share",
|
||||
callback: function(aTarget) { }
|
||||
});
|
||||
|
||||
NativeWindow.contextmenus.add(Strings.browser.GetStringFromName("contextmenu.sharePhoneNumber"),
|
||||
NativeWindow.contextmenus._disableInGuest(NativeWindow.contextmenus.phoneNumberLinkContext),
|
||||
function(aTarget) {
|
||||
let url = NativeWindow.contextmenus._getLinkURL(aTarget);
|
||||
let phoneNumber = NativeWindow.contextmenus._stripScheme(url);
|
||||
let title = aTarget.textContent || aTarget.title;
|
||||
NativeWindow.contextmenus._shareStringWithDefault(phoneNumber, title);
|
||||
});
|
||||
NativeWindow.contextmenus.add({
|
||||
label: Strings.browser.GetStringFromName("contextmenu.sharePhoneNumber"),
|
||||
order: NativeWindow.contextmenus.DEFAULT_HTML5_ORDER - 1,
|
||||
selector: NativeWindow.contextmenus._disableInGuest(NativeWindow.contextmenus.phoneNumberLinkContext),
|
||||
showAsActions: function(aElement) {
|
||||
let url = NativeWindow.contextmenus._getLinkURL(aElement);
|
||||
let [, phoneNumber] = NativeWindow.contextmenus._stripScheme(url);
|
||||
let title = aElement.textContent || aElement.title;
|
||||
return {
|
||||
title: title,
|
||||
uri: phoneNumber,
|
||||
type: "text/tel",
|
||||
}
|
||||
},
|
||||
icon: "drawable://ic_menu_share",
|
||||
callback: function(aTarget) { }
|
||||
});
|
||||
|
||||
NativeWindow.contextmenus.add(Strings.browser.GetStringFromName("contextmenu.addToContacts"),
|
||||
NativeWindow.contextmenus._disableInGuest(NativeWindow.contextmenus.emailLinkContext),
|
||||
|
@ -596,13 +620,23 @@ var BrowserApp = {
|
|||
aTarget.setAttribute("controls", true);
|
||||
});
|
||||
|
||||
NativeWindow.contextmenus.add(Strings.browser.GetStringFromName("contextmenu.shareMedia"),
|
||||
NativeWindow.contextmenus._disableInGuest(NativeWindow.contextmenus.SelectorContext("video")),
|
||||
function(aTarget) {
|
||||
let url = (aTarget.currentSrc || aTarget.src);
|
||||
let title = aTarget.textContent || aTarget.title;
|
||||
NativeWindow.contextmenus._shareStringWithDefault(url, title);
|
||||
});
|
||||
NativeWindow.contextmenus.add({
|
||||
label: Strings.browser.GetStringFromName("contextmenu.shareMedia"),
|
||||
order: NativeWindow.contextmenus.DEFAULT_HTML5_ORDER-1,
|
||||
selector: NativeWindow.contextmenus._disableInGuest(NativeWindow.contextmenus.SelectorContext("video")),
|
||||
showAsActions: function(aElement) {
|
||||
let url = (aElement.currentSrc || aElement.src);
|
||||
let title = aElement.textContent || aElement.title;
|
||||
return {
|
||||
title: title,
|
||||
uri: url,
|
||||
type: "video/*",
|
||||
}
|
||||
},
|
||||
icon: "drawable://ic_menu_share",
|
||||
callback: function(aTarget) {
|
||||
}
|
||||
});
|
||||
|
||||
NativeWindow.contextmenus.add(Strings.browser.GetStringFromName("contextmenu.fullScreen"),
|
||||
NativeWindow.contextmenus.SelectorContext("video:not(:-moz-full-screen)"),
|
||||
|
@ -629,26 +663,26 @@ var BrowserApp = {
|
|||
NativeWindow.contextmenus._copyStringToDefaultClipboard(url);
|
||||
});
|
||||
|
||||
NativeWindow.contextmenus.add(Strings.browser.GetStringFromName("contextmenu.shareImage"),
|
||||
NativeWindow.contextmenus._disableInGuest(NativeWindow.contextmenus.imageSaveableContext),
|
||||
function(aTarget) {
|
||||
NativeWindow.contextmenus.add({
|
||||
label: Strings.browser.GetStringFromName("contextmenu.shareImage"),
|
||||
selector: NativeWindow.contextmenus._disableInGuest(NativeWindow.contextmenus.imageSaveableContext),
|
||||
order: NativeWindow.contextmenus.DEFAULT_HTML5_ORDER-1, // Show above HTML5 menu items
|
||||
showAsActions: function(aTarget) {
|
||||
let doc = aTarget.ownerDocument;
|
||||
let imageCache = Cc["@mozilla.org/image/tools;1"].getService(Ci.imgITools)
|
||||
.getImgCacheForDocument(doc);
|
||||
let props = imageCache.findEntryProperties(aTarget.currentURI, doc.characterSet);
|
||||
let src = aTarget.src;
|
||||
let type = "";
|
||||
try {
|
||||
type = String(props.get("type", Ci.nsISupportsCString));
|
||||
} catch(ex) {
|
||||
type = "";
|
||||
return {
|
||||
title: src,
|
||||
uri: src,
|
||||
type: "image/*",
|
||||
}
|
||||
sendMessageToJava({
|
||||
type: "Share:Image",
|
||||
url: src,
|
||||
mime: type,
|
||||
});
|
||||
});
|
||||
},
|
||||
icon: "drawable://ic_menu_share",
|
||||
menu: true,
|
||||
callback: function(aTarget) { }
|
||||
});
|
||||
|
||||
NativeWindow.contextmenus.add(Strings.browser.GetStringFromName("contextmenu.saveImage"),
|
||||
NativeWindow.contextmenus.imageSaveableContext,
|
||||
|
@ -2205,13 +2239,13 @@ var NativeWindow = {
|
|||
|
||||
_getUrl: function(node) {
|
||||
if ((node instanceof Ci.nsIDOMHTMLAnchorElement && node.href) ||
|
||||
(node instanceof Ci.nsIDOMHTMLAreaElement && node.href)) {
|
||||
return this._getLinkURL(node);
|
||||
} else if (node instanceof Ci.nsIImageLoadingContent && node.currentURI) {
|
||||
return node.currentURI.spec;
|
||||
} else if (node instanceof Ci.nsIDOMHTMLMediaElement) {
|
||||
return (node.currentSrc || node.src);
|
||||
}
|
||||
|
||||
return "";
|
||||
},
|
||||
|
||||
|
@ -2283,7 +2317,10 @@ var NativeWindow = {
|
|||
let title = this._findTitle(target);
|
||||
|
||||
this.menuitems.sort((a,b) => {
|
||||
if (a.order == b.order) return 0;
|
||||
if (a.order == b.order) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (a.order > b.order) ? 1 : -1;
|
||||
});
|
||||
|
||||
|
@ -2393,7 +2430,8 @@ var NativeWindow = {
|
|||
},
|
||||
|
||||
_stripScheme: function(aString) {
|
||||
return aString.slice(aString.indexOf(":") + 1);
|
||||
let index = aString.indexOf(":");
|
||||
return [aString.slice(0, index), aString.slice(index + 1)];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -8313,7 +8351,7 @@ ContextMenuItem.prototype = {
|
|||
return {
|
||||
id: this.id,
|
||||
label: this.addVal("label", elt),
|
||||
shareData: this.addVal("shareData", elt),
|
||||
showAsActions: this.addVal("showAsActions", elt),
|
||||
icon: this.addVal("icon", elt),
|
||||
isGroup: this.addVal("isGroup", elt, false),
|
||||
inGroup: this.addVal("inGroup", elt, false),
|
||||
|
|
|
@ -195,6 +195,12 @@ Prompt.prototype = {
|
|||
if (item.child)
|
||||
obj.inGroup = true;
|
||||
|
||||
if (item.showAsActions)
|
||||
obj.showAsActions = item.showAsActions;
|
||||
|
||||
if (item.icon)
|
||||
obj.icon = item.icon;
|
||||
|
||||
this.msg.listitems.push(obj);
|
||||
|
||||
}, this);
|
||||
|
|
Загрузка…
Ссылка в новой задаче