зеркало из https://github.com/mozilla/gecko-dev.git
Merge fx-team to m-c a=merge
This commit is contained in:
Коммит
88eab9e3b2
|
@ -398,8 +398,7 @@ panel[noactions] > richlistbox > richlistitem[type~="action"] > .ac-url-box > .a
|
|||
visibility: visible;
|
||||
}
|
||||
|
||||
#urlbar:not([actiontype]) > #urlbar-display-box,
|
||||
#urlbar:not([actiontype="switchtab"]) > #urlbar-display-box > .urlbar-display-switchtab {
|
||||
#urlbar:not([actiontype="switchtab"]) > #urlbar-display-box {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
|
|
@ -425,7 +425,7 @@ this.GoogleImporter.prototype = {
|
|||
if (Object.keys(adr).length) {
|
||||
adr.pref = (addressNode.getAttribute("primary") == "true");
|
||||
adr.type = [getFieldType(addressNode)];
|
||||
contacts.adr.push(adr);
|
||||
contact.adr.push(adr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -58,6 +58,13 @@
|
|||
|
||||
// Local mocks
|
||||
|
||||
var mockContact = {
|
||||
name: ["Mr Smith"],
|
||||
email: [{
|
||||
value: "smith@invalid.com"
|
||||
}]
|
||||
};
|
||||
|
||||
var mockClient = {
|
||||
requestCallUrl: noop,
|
||||
requestCallUrlInfo: noop
|
||||
|
@ -254,7 +261,8 @@
|
|||
Example({summary: "Connecting", dashed: "true",
|
||||
style: {width: "260px", height: "265px"}},
|
||||
React.DOM.div({className: "fx-embedded"},
|
||||
DesktopPendingConversationView({callState: "gather", calleeId: "Mr Smith"})
|
||||
DesktopPendingConversationView({callState: "gather",
|
||||
contact: mockContact})
|
||||
)
|
||||
)
|
||||
),
|
||||
|
|
|
@ -58,6 +58,13 @@
|
|||
|
||||
// Local mocks
|
||||
|
||||
var mockContact = {
|
||||
name: ["Mr Smith"],
|
||||
email: [{
|
||||
value: "smith@invalid.com"
|
||||
}]
|
||||
};
|
||||
|
||||
var mockClient = {
|
||||
requestCallUrl: noop,
|
||||
requestCallUrlInfo: noop
|
||||
|
@ -254,7 +261,8 @@
|
|||
<Example summary="Connecting" dashed="true"
|
||||
style={{width: "260px", height: "265px"}}>
|
||||
<div className="fx-embedded">
|
||||
<DesktopPendingConversationView callState={"gather"} calleeId="Mr Smith" />
|
||||
<DesktopPendingConversationView callState={"gather"}
|
||||
contact={mockContact} />
|
||||
</div>
|
||||
</Example>
|
||||
</Section>
|
||||
|
|
|
@ -191,7 +191,7 @@ public class BrowserApp extends GeckoApp
|
|||
public boolean added; // So we can re-add after a locale change.
|
||||
}
|
||||
|
||||
// The types of guest mdoe dialogs we show
|
||||
// The types of guest mode dialogs we show.
|
||||
public static enum GuestModeDialog {
|
||||
ENTERING,
|
||||
LEAVING
|
||||
|
@ -520,11 +520,12 @@ public class BrowserApp extends GeckoApp
|
|||
mAboutHomeStartupTimer = new Telemetry.UptimeTimer("FENNEC_STARTUP_TIME_ABOUTHOME");
|
||||
|
||||
final Intent intent = getIntent();
|
||||
final String args = intent.getStringExtra("args");
|
||||
|
||||
if (GuestSession.shouldUse(this, args)) {
|
||||
mProfile = GeckoProfile.createGuestProfile(this);
|
||||
} else {
|
||||
final GeckoProfile p = GeckoProfile.get(this);
|
||||
if (p != null && !p.inGuestMode()) {
|
||||
// This is *only* valid because we never want to use the guest mode
|
||||
// profile concurrently with a normal profile -- no syncing to it,
|
||||
// no dual-profile usage, nothing. BrowserApp startup with a conventional
|
||||
// GeckoProfile will cause the guest profile to be deleted.
|
||||
GeckoProfile.maybeCleanupGuestProfile(this);
|
||||
}
|
||||
|
||||
|
@ -673,13 +674,6 @@ public class BrowserApp extends GeckoApp
|
|||
Log.e(LOGTAG, "Error initializing media manager", ex);
|
||||
}
|
||||
}
|
||||
|
||||
if (getProfile().inGuestMode()) {
|
||||
GuestSession.showNotification(this);
|
||||
} else {
|
||||
// If we're restarting, we won't destroy the activity. Make sure we remove any guest notifications that might have been shown.
|
||||
GuestSession.hideNotification(this);
|
||||
}
|
||||
}
|
||||
|
||||
private void setupSystemUITinting() {
|
||||
|
@ -790,6 +784,35 @@ public class BrowserApp extends GeckoApp
|
|||
lbm.unregisterReceiver(mOnboardingReceiver);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
|
||||
// Queue this work so that the first launch of the activity doesn't
|
||||
// trigger profile init too early.
|
||||
ThreadUtils.postToBackgroundThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (getProfile().inGuestMode()) {
|
||||
GuestSession.showNotification(BrowserApp.this);
|
||||
} else {
|
||||
// If we're restarting, we won't destroy the activity.
|
||||
// Make sure we remove any guest notifications that might
|
||||
// have been shown.
|
||||
GuestSession.hideNotification(BrowserApp.this);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop() {
|
||||
super.onStop();
|
||||
|
||||
// We only show the guest mode notification when our activity is in the foreground.
|
||||
GuestSession.hideNotification(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWindowFocusChanged(boolean hasFocus) {
|
||||
super.onWindowFocusChanged(hasFocus);
|
||||
|
@ -1087,8 +1110,6 @@ public class BrowserApp extends GeckoApp
|
|||
mBrowserHealthReporter = null;
|
||||
}
|
||||
|
||||
GuestSession.onDestroy(this);
|
||||
|
||||
EventDispatcher.getInstance().unregisterGeckoThreadListener((GeckoEventListener)this,
|
||||
"Menu:Update",
|
||||
"Reader:Added",
|
||||
|
@ -2939,6 +2960,9 @@ public class BrowserApp extends GeckoApp
|
|||
args = GUEST_BROWSING_ARG;
|
||||
} else {
|
||||
GeckoProfile.leaveGuestSession(BrowserApp.this);
|
||||
|
||||
// Now's a good time to make sure we're not displaying the Guest Browsing notification.
|
||||
GuestSession.hideNotification(BrowserApp.this);
|
||||
}
|
||||
|
||||
if (!GuestSession.isSecureKeyguardLocked(BrowserApp.this)) {
|
||||
|
|
|
@ -193,7 +193,8 @@ class ChromeCast implements GeckoMediaPlayer {
|
|||
.addConnectionCallbacks(new GoogleApiClient.ConnectionCallbacks() {
|
||||
@Override
|
||||
public void onConnected(Bundle connectionHint) {
|
||||
if (!apiClient.isConnected()) {
|
||||
// Sometimes apiClient is null here. See bug 1061032
|
||||
if (apiClient != null && !apiClient.isConnected()) {
|
||||
debug("Connection failed");
|
||||
callback.sendError("Not connected");
|
||||
return;
|
||||
|
@ -253,18 +254,23 @@ class ChromeCast implements GeckoMediaPlayer {
|
|||
return;
|
||||
}
|
||||
|
||||
remoteMediaPlayer.play(apiClient).setResultCallback(new ResultCallback<MediaChannelResult>() {
|
||||
@Override
|
||||
public void onResult(MediaChannelResult result) {
|
||||
Status status = result.getStatus();
|
||||
if (!status.isSuccess()) {
|
||||
debug("Unable to play: " + status.getStatusCode());
|
||||
callback.sendError(status.toString());
|
||||
} else {
|
||||
callback.sendSuccess(null);
|
||||
try {
|
||||
remoteMediaPlayer.play(apiClient).setResultCallback(new ResultCallback<MediaChannelResult>() {
|
||||
@Override
|
||||
public void onResult(MediaChannelResult result) {
|
||||
Status status = result.getStatus();
|
||||
if (!status.isSuccess()) {
|
||||
debug("Unable to play: " + status.getStatusCode());
|
||||
callback.sendError(status.toString());
|
||||
} else {
|
||||
callback.sendSuccess(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
} catch(IllegalStateException ex) {
|
||||
// The media player may throw if the session has been killed. For now, we're just catching this here.
|
||||
callback.sendError("Error playing");
|
||||
}
|
||||
}
|
||||
|
||||
public void pause(final EventCallback callback) {
|
||||
|
@ -272,18 +278,23 @@ class ChromeCast implements GeckoMediaPlayer {
|
|||
return;
|
||||
}
|
||||
|
||||
remoteMediaPlayer.pause(apiClient).setResultCallback(new ResultCallback<MediaChannelResult>() {
|
||||
@Override
|
||||
public void onResult(MediaChannelResult result) {
|
||||
Status status = result.getStatus();
|
||||
if (!status.isSuccess()) {
|
||||
debug("Unable to pause: " + status.getStatusCode());
|
||||
callback.sendError(status.toString());
|
||||
} else {
|
||||
callback.sendSuccess(null);
|
||||
try {
|
||||
remoteMediaPlayer.pause(apiClient).setResultCallback(new ResultCallback<MediaChannelResult>() {
|
||||
@Override
|
||||
public void onResult(MediaChannelResult result) {
|
||||
Status status = result.getStatus();
|
||||
if (!status.isSuccess()) {
|
||||
debug("Unable to pause: " + status.getStatusCode());
|
||||
callback.sendError(status.toString());
|
||||
} else {
|
||||
callback.sendSuccess(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
} catch(IllegalStateException ex) {
|
||||
// The media player may throw if the session has been killed. For now, we're just catching this here.
|
||||
callback.sendError("Error pausing");
|
||||
}
|
||||
}
|
||||
|
||||
public void end(final EventCallback callback) {
|
||||
|
@ -291,32 +302,37 @@ class ChromeCast implements GeckoMediaPlayer {
|
|||
return;
|
||||
}
|
||||
|
||||
Cast.CastApi.stopApplication(apiClient).setResultCallback(new ResultCallback<Status>() {
|
||||
@Override
|
||||
public void onResult(Status result) {
|
||||
if (result.isSuccess()) {
|
||||
try {
|
||||
Cast.CastApi.removeMessageReceivedCallbacks(apiClient, remoteMediaPlayer.getNamespace());
|
||||
remoteMediaPlayer = null;
|
||||
mSessionId = null;
|
||||
apiClient.disconnect();
|
||||
apiClient = null;
|
||||
try {
|
||||
Cast.CastApi.stopApplication(apiClient).setResultCallback(new ResultCallback<Status>() {
|
||||
@Override
|
||||
public void onResult(Status result) {
|
||||
if (result.isSuccess()) {
|
||||
try {
|
||||
Cast.CastApi.removeMessageReceivedCallbacks(apiClient, remoteMediaPlayer.getNamespace());
|
||||
remoteMediaPlayer = null;
|
||||
mSessionId = null;
|
||||
apiClient.disconnect();
|
||||
apiClient = null;
|
||||
|
||||
if (callback != null) {
|
||||
callback.sendSuccess(null);
|
||||
if (callback != null) {
|
||||
callback.sendSuccess(null);
|
||||
}
|
||||
|
||||
return;
|
||||
} catch(Exception ex) {
|
||||
debug("Error ending", ex);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
} catch(Exception ex) {
|
||||
debug("Error ending", ex);
|
||||
if (callback != null) {
|
||||
callback.sendError(result.getStatus().toString());
|
||||
}
|
||||
}
|
||||
|
||||
if (callback != null) {
|
||||
callback.sendError(result.getStatus().toString());
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
} catch(IllegalStateException ex) {
|
||||
// The media player may throw if the session has been killed. For now, we're just catching this here.
|
||||
callback.sendError("Error stopping");
|
||||
}
|
||||
}
|
||||
|
||||
class MirrorChannel implements MessageReceivedCallback {
|
||||
|
@ -413,7 +429,8 @@ class ChromeCast implements GeckoMediaPlayer {
|
|||
.addConnectionCallbacks(new GoogleApiClient.ConnectionCallbacks() {
|
||||
@Override
|
||||
public void onConnected(Bundle connectionHint) {
|
||||
if (!apiClient.isConnected()) {
|
||||
// Sometimes apiClient is null here. See bug 1061032
|
||||
if (apiClient == null || !apiClient.isConnected()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -9,7 +9,6 @@ import java.io.ByteArrayOutputStream;
|
|||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
|
@ -45,7 +44,6 @@ import org.mozilla.gecko.mozglue.GeckoLoader;
|
|||
import org.mozilla.gecko.preferences.ClearOnShutdownPref;
|
||||
import org.mozilla.gecko.preferences.GeckoPreferences;
|
||||
import org.mozilla.gecko.prompts.PromptService;
|
||||
import org.mozilla.gecko.SmsManager;
|
||||
import org.mozilla.gecko.updater.UpdateService;
|
||||
import org.mozilla.gecko.updater.UpdateServiceHelper;
|
||||
import org.mozilla.gecko.util.ActivityResultHandler;
|
||||
|
@ -443,6 +441,9 @@ public abstract class GeckoApp
|
|||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
if (item.getItemId() == R.id.quit) {
|
||||
// Make sure the Guest Browsing notification goes away when we quit.
|
||||
GuestSession.hideNotification(this);
|
||||
|
||||
if (GeckoThread.checkAndSetLaunchState(GeckoThread.LaunchState.GeckoRunning, GeckoThread.LaunchState.GeckoExiting)) {
|
||||
final SharedPreferences prefs = GeckoSharedPrefs.forProfile(this);
|
||||
final Set<String> clearSet = PrefUtils.getStringSet(prefs, ClearOnShutdownPref.PREF, new HashSet<String>());
|
||||
|
|
|
@ -23,6 +23,7 @@ import org.mozilla.gecko.mozglue.RobocopTarget;
|
|||
import org.mozilla.gecko.util.INIParser;
|
||||
import org.mozilla.gecko.util.INISection;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
@ -90,9 +91,19 @@ public final class GeckoProfile {
|
|||
}
|
||||
}
|
||||
|
||||
// If the guest profile should be used return it.
|
||||
if (GuestSession.shouldUse(context, "")) {
|
||||
return GeckoProfile.getGuestProfile(context);
|
||||
final String args;
|
||||
if (context instanceof Activity) {
|
||||
args = ((Activity) context).getIntent().getStringExtra("args");
|
||||
} else {
|
||||
args = null;
|
||||
}
|
||||
|
||||
if (GuestSession.shouldUse(context, args)) {
|
||||
GeckoProfile p = GeckoProfile.getOrCreateGuestProfile(context);
|
||||
if (isGeckoApp) {
|
||||
((GeckoApp) context).mProfile = p;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
if (isGeckoApp) {
|
||||
|
@ -191,6 +202,8 @@ public final class GeckoProfile {
|
|||
return success;
|
||||
}
|
||||
|
||||
// Only public for access from tests.
|
||||
@RobocopTarget
|
||||
public static GeckoProfile createGuestProfile(Context context) {
|
||||
try {
|
||||
// We need to force the creation of a new guest profile if we want it outside of the normal profile path,
|
||||
|
@ -232,6 +245,18 @@ public final class GeckoProfile {
|
|||
return sGuestDir;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs IO. Be careful of using this on the main thread.
|
||||
*/
|
||||
public static GeckoProfile getOrCreateGuestProfile(Context context) {
|
||||
GeckoProfile p = getGuestProfile(context);
|
||||
if (p == null) {
|
||||
return createGuestProfile(context);
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
public static GeckoProfile getGuestProfile(Context context) {
|
||||
if (sGuestProfile == null) {
|
||||
File guestDir = getGuestDir(context);
|
||||
|
|
|
@ -4,29 +4,15 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
package org.mozilla.gecko;
|
||||
|
||||
import android.app.NotificationManager;
|
||||
import android.app.KeyguardManager;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Resources;
|
||||
import android.net.Uri;
|
||||
import android.util.Log;
|
||||
import android.support.v4.app.NotificationCompat;
|
||||
import android.view.Window;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.ListView;
|
||||
import android.support.v4.app.NotificationCompat;
|
||||
|
||||
import org.mozilla.gecko.prompts.Prompt;
|
||||
import org.mozilla.gecko.util.EventCallback;
|
||||
import org.mozilla.gecko.util.NativeEventListener;
|
||||
import org.mozilla.gecko.util.NativeJSObject;
|
||||
import org.mozilla.gecko.util.ThreadUtils;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
// Utility methods for entering/exiting guest mode.
|
||||
public class GuestSession {
|
||||
|
@ -105,12 +91,6 @@ public class GuestSession {
|
|||
manager.cancel(R.id.guestNotification);
|
||||
}
|
||||
|
||||
public static void onDestroy(Context context) {
|
||||
if (GeckoProfile.get(context).inGuestMode()) {
|
||||
hideNotification(context);
|
||||
}
|
||||
}
|
||||
|
||||
public static void handleIntent(BrowserApp context, Intent intent) {
|
||||
context.showGuestModeDialog(BrowserApp.GuestModeDialog.LEAVING);
|
||||
}
|
||||
|
|
|
@ -182,7 +182,7 @@
|
|||
<!ENTITY pref_char_encoding_off "Don\'t show menu">
|
||||
<!ENTITY pref_clear_private_data2 "Clear now">
|
||||
<!ENTITY pref_clear_private_data_category "Clear private data">
|
||||
<!ENTITY pref_clear_on_exit_title "Always clear when quitting">
|
||||
<!ENTITY pref_clear_on_exit_title2 "Clear on exit">
|
||||
<!ENTITY pref_clear_on_exit_summary2 "&brandShortName; will automatically clear your data whenever you select \u0022Quit\u0022 from the main menu">
|
||||
<!ENTITY pref_clear_on_exit_dialog_title "Select which data to clear">
|
||||
<!ENTITY pref_plugins "Plugins">
|
||||
|
|
|
@ -191,7 +191,7 @@
|
|||
<string name="pref_char_encoding_off">&pref_char_encoding_off;</string>
|
||||
<string name="pref_clear_private_data">&pref_clear_private_data2;</string>
|
||||
<string name="pref_clear_private_data_category">&pref_clear_private_data_category;</string>
|
||||
<string name="pref_clear_on_exit_title">&pref_clear_on_exit_title;</string>
|
||||
<string name="pref_clear_on_exit_title">&pref_clear_on_exit_title2;</string>
|
||||
<string name="pref_clear_on_exit_summary2">&pref_clear_on_exit_summary2;</string>
|
||||
<string name="pref_clear_on_exit_dialog_title">&pref_clear_on_exit_dialog_title;</string>
|
||||
<string name="pref_plugins">&pref_plugins;</string>
|
||||
|
|
|
@ -55,7 +55,7 @@ class TabsGridLayout extends GridView
|
|||
@Override
|
||||
public void onMovedToScrapHeap(View view) {
|
||||
TabsLayoutItemView item = (TabsLayoutItemView) view;
|
||||
item.thumbnail.setImageDrawable(null);
|
||||
item.setThumbnail(null);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -72,7 +72,7 @@ class TabsGridLayout extends GridView
|
|||
@Override
|
||||
public void onClick(View v) {
|
||||
TabsLayoutItemView itemView = (TabsLayoutItemView) v.getTag();
|
||||
Tab tab = Tabs.getInstance().getTab(itemView.id);
|
||||
Tab tab = Tabs.getInstance().getTab(itemView.getTabId());
|
||||
Tabs.getInstance().closeTab(tab);
|
||||
}
|
||||
};
|
||||
|
@ -81,7 +81,7 @@ class TabsGridLayout extends GridView
|
|||
@Override
|
||||
public void onClick(View v) {
|
||||
TabsLayoutItemView tab = (TabsLayoutItemView) v;
|
||||
Tabs.getInstance().selectTab(tab.id);
|
||||
Tabs.getInstance().selectTab(tab.getTabId());
|
||||
autoHidePanel();
|
||||
}
|
||||
};
|
||||
|
|
|
@ -24,13 +24,11 @@ public class TabsLayoutItemView extends LinearLayout
|
|||
private static final int[] STATE_CHECKED = { android.R.attr.state_checked };
|
||||
private boolean mChecked;
|
||||
|
||||
// yeah, it's a bit nasty having two different styles for the class members,
|
||||
// this'll be fixed once bug 1058574 is addressed
|
||||
int id;
|
||||
TextView title;
|
||||
ImageView thumbnail;
|
||||
ImageButton close;
|
||||
TabThumbnailWrapper thumbnailWrapper;
|
||||
private int mTabId;
|
||||
private TextView mTitle;
|
||||
private ImageView mThumbnail;
|
||||
private ImageButton mCloseButton;
|
||||
private TabThumbnailWrapper mThumbnailWrapper;
|
||||
|
||||
public TabsLayoutItemView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
|
@ -76,16 +74,16 @@ public class TabsLayoutItemView extends LinearLayout
|
|||
}
|
||||
|
||||
public void setCloseOnClickListener(OnClickListener mOnClickListener) {
|
||||
close.setOnClickListener(mOnClickListener);
|
||||
mCloseButton.setOnClickListener(mOnClickListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onFinishInflate() {
|
||||
super.onFinishInflate();
|
||||
title = (TextView) findViewById(R.id.title);
|
||||
thumbnail = (ImageView) findViewById(R.id.thumbnail);
|
||||
close = (ImageButton) findViewById(R.id.close);
|
||||
thumbnailWrapper = (TabThumbnailWrapper) findViewById(R.id.wrapper);
|
||||
mTitle = (TextView) findViewById(R.id.title);
|
||||
mThumbnail = (ImageView) findViewById(R.id.thumbnail);
|
||||
mCloseButton = (ImageButton) findViewById(R.id.close);
|
||||
mThumbnailWrapper = (TabThumbnailWrapper) findViewById(R.id.wrapper);
|
||||
}
|
||||
|
||||
protected void assignValues(Tab tab) {
|
||||
|
@ -93,18 +91,30 @@ public class TabsLayoutItemView extends LinearLayout
|
|||
return;
|
||||
}
|
||||
|
||||
id = tab.getId();
|
||||
mTabId = tab.getId();
|
||||
|
||||
Drawable thumbnailImage = tab.getThumbnail();
|
||||
if (thumbnailImage != null) {
|
||||
thumbnail.setImageDrawable(thumbnailImage);
|
||||
mThumbnail.setImageDrawable(thumbnailImage);
|
||||
} else {
|
||||
thumbnail.setImageResource(R.drawable.tab_thumbnail_default);
|
||||
mThumbnail.setImageResource(R.drawable.tab_thumbnail_default);
|
||||
}
|
||||
if (thumbnailWrapper != null) {
|
||||
thumbnailWrapper.setRecording(tab.isRecording());
|
||||
if (mThumbnailWrapper != null) {
|
||||
mThumbnailWrapper.setRecording(tab.isRecording());
|
||||
}
|
||||
title.setText(tab.getDisplayTitle());
|
||||
close.setTag(this);
|
||||
mTitle.setText(tab.getDisplayTitle());
|
||||
mCloseButton.setTag(this);
|
||||
}
|
||||
|
||||
public int getTabId() {
|
||||
return mTabId;
|
||||
}
|
||||
|
||||
public void setThumbnail(Drawable thumbnail) {
|
||||
mThumbnail.setImageDrawable(thumbnail);
|
||||
}
|
||||
|
||||
public void setCloseVisibile(boolean visible) {
|
||||
mCloseButton.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -80,8 +80,8 @@ class TabsListLayout extends TwoWayView
|
|||
@Override
|
||||
public void onMovedToScrapHeap(View view) {
|
||||
TabsLayoutItemView item = (TabsLayoutItemView) view;
|
||||
item.thumbnail.setImageDrawable(null);
|
||||
item.close.setVisibility(View.VISIBLE);
|
||||
item.setThumbnail(null);
|
||||
item.setCloseVisibile(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -360,7 +360,7 @@ class TabsListLayout extends TwoWayView
|
|||
else
|
||||
animator.attach(view, Property.WIDTH, 1);
|
||||
|
||||
final int tabId = ((TabsLayoutItemView) view).id;
|
||||
final int tabId = ((TabsLayoutItemView) view).getTabId();
|
||||
|
||||
// Caching this assumes that all rows are the same height
|
||||
if (mOriginalSize == 0) {
|
||||
|
@ -397,7 +397,7 @@ class TabsListLayout extends TwoWayView
|
|||
@Override
|
||||
public void onPropertyAnimationEnd() {
|
||||
TabsLayoutItemView tab = (TabsLayoutItemView) view;
|
||||
tab.close.setVisibility(View.VISIBLE);
|
||||
tab.setCloseVisibile(true);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -495,7 +495,7 @@ class TabsListLayout extends TwoWayView
|
|||
|
||||
if (!mSwiping) {
|
||||
TabsLayoutItemView item = (TabsLayoutItemView) mSwipeView;
|
||||
Tabs.getInstance().selectTab(item.id);
|
||||
Tabs.getInstance().selectTab(item.getTabId());
|
||||
autoHidePanel();
|
||||
|
||||
mVelocityTracker.recycle();
|
||||
|
@ -582,7 +582,7 @@ class TabsListLayout extends TwoWayView
|
|||
mSwiping = true;
|
||||
TabsListLayout.this.requestDisallowInterceptTouchEvent(true);
|
||||
|
||||
((TabsLayoutItemView) mSwipeView).close.setVisibility(View.INVISIBLE);
|
||||
((TabsLayoutItemView) mSwipeView).setCloseVisibile(false);
|
||||
|
||||
// Stops listview from highlighting the touched item
|
||||
// in the list when swiping.
|
||||
|
|
|
@ -119,7 +119,7 @@ HelperAppLauncherDialog.prototype = {
|
|||
|
||||
Services.console.logStringMessage("Refusing download of non-downloadable file.");
|
||||
let bundle = Services.strings.createBundle("chrome://browser/locale/handling.properties");
|
||||
let failedText = bundle.GetStringFromName("protocol.failed");
|
||||
let failedText = bundle.GetStringFromName("download.blocked");
|
||||
win.toast.show(failedText, "long");
|
||||
|
||||
return;
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
# 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/.
|
||||
|
||||
download.blocked=Unable to download file
|
||||
protocol.failed=Couldn't find an app to open this link
|
||||
# A very short string shown in the button toast when no application can open the url
|
||||
protocol.toast.search=Search
|
||||
|
|
|
@ -142,9 +142,10 @@ class XPCShellRunner(MozbuildObject):
|
|||
modules_dir = os.path.join(self.topobjdir, '_tests', 'modules')
|
||||
# We want output from the test to be written immediately if we are only
|
||||
# running a single test.
|
||||
verbose_output = (test_path is not None or
|
||||
(manifest and len(manifest.test_paths())==1) or
|
||||
verbose)
|
||||
single_test = (test_path is not None or
|
||||
(manifest and len(manifest.test_paths())==1))
|
||||
verbose_output = verbose or single_test
|
||||
sequential = sequential or single_test
|
||||
|
||||
args = {
|
||||
'manifest': manifest,
|
||||
|
|
|
@ -7,8 +7,8 @@
|
|||
/**
|
||||
* This module provides an asynchronous API for managing bookmarks.
|
||||
*
|
||||
* Bookmarks are organized in a tree structure, and can be bookmarked URIs,
|
||||
* folders or separators. Multiple bookmarks for the same URI are allowed.
|
||||
* Bookmarks are organized in a tree structure, and can be bookmarked URLs,
|
||||
* folders or separators. Multiple bookmarks for the same URL are allowed.
|
||||
*
|
||||
* Note that if you are handling bookmarks operations in the UI, you should
|
||||
* not use this API directly, but rather use PlacesTransactions.jsm, so that
|
||||
|
@ -24,10 +24,10 @@
|
|||
* This will be an empty string for the Places root folder.
|
||||
* - index (number)
|
||||
* The 0-based position of the item in the parent folder.
|
||||
* - dateAdded (number, microseconds from the epoch)
|
||||
* The time at which the item was added. This is a PRTime (microseconds).
|
||||
* - lastModified (number, microseconds from the epoch)
|
||||
* The time at which the item was last modified. This is a PRTime (microseconds).
|
||||
* - dateAdded (Date)
|
||||
* The time at which the item was added.
|
||||
* - lastModified (Date)
|
||||
* The time at which the item was last modified.
|
||||
* - type (number)
|
||||
* The item's type, either TYPE_BOOKMARK, TYPE_FOLDER or TYPE_SEPARATOR.
|
||||
*
|
||||
|
@ -36,11 +36,16 @@
|
|||
* - title (string)
|
||||
* The item's title, if any. Empty titles and null titles are considered
|
||||
* the same and the property is unset on retrieval in such a case.
|
||||
* Title cannot be longer than TITLE_LENGTH_MAX, or it will be truncated.
|
||||
*
|
||||
* The following properties are only valid for bookmarks:
|
||||
*
|
||||
* - uri (nsIURI)
|
||||
* The item's URI.
|
||||
* - url (URL, href or nsIURI)
|
||||
* The item's URL. Note that while input objects can contains either
|
||||
* an URL object, an href string, or an nsIURI, output objects will always
|
||||
* contain an URL object.
|
||||
* URL cannot be longer than URL_LENGTH_MAX, methods will throw if a
|
||||
* longer value is provided
|
||||
* - keyword (string)
|
||||
* The associated keyword, if any.
|
||||
*
|
||||
|
@ -53,9 +58,6 @@
|
|||
* property) won't fire an onItemChanged notification for the lastModified
|
||||
* property.
|
||||
* @see nsINavBookmarkObserver
|
||||
*
|
||||
* @note livemarks are implemented as empty folders.
|
||||
* @see mozIAsyncLivemarks.idl
|
||||
*/
|
||||
|
||||
this.EXPORTED_SYMBOLS = [ "Bookmarks" ];
|
||||
|
@ -74,7 +76,7 @@ XPCOMUtils.defineLazyModuleGetter(this, "Task",
|
|||
XPCOMUtils.defineLazyModuleGetter(this, "Sqlite",
|
||||
"resource://gre/modules/Sqlite.jsm");
|
||||
|
||||
const URI_LENGTH_MAX = 65536;
|
||||
const URL_LENGTH_MAX = 65536;
|
||||
const TITLE_LENGTH_MAX = 4096;
|
||||
|
||||
let Bookmarks = Object.freeze({
|
||||
|
@ -86,6 +88,12 @@ let Bookmarks = Object.freeze({
|
|||
TYPE_FOLDER: 2,
|
||||
TYPE_SEPARATOR: 3,
|
||||
|
||||
/**
|
||||
* Default index used to append a bookmarked item at the end of a container.
|
||||
* This should stay consistent with nsINavBookmarksService.idl
|
||||
*/
|
||||
DEFAULT_INDEX: -1,
|
||||
|
||||
/**
|
||||
* Creates or updates a bookmarked item.
|
||||
*
|
||||
|
@ -96,7 +104,7 @@ let Bookmarks = Object.freeze({
|
|||
* In the creation case, a minimum set of properties must be provided:
|
||||
* - type
|
||||
* - parentGuid
|
||||
* - URI, only for bookmarks
|
||||
* - url, only for bookmarks
|
||||
* If an index is not specified, it defaults to appending.
|
||||
* It's also possible to pass a non-existent guid to force creation of an
|
||||
* item with the given guid, but unless you have a very sound reason, such as
|
||||
|
@ -111,17 +119,19 @@ let Bookmarks = Object.freeze({
|
|||
* associated with this bookmark.
|
||||
*
|
||||
* Note that any known property that doesn't apply to the specific item type
|
||||
* causes rejection.
|
||||
* throws an exception.
|
||||
*
|
||||
* @param info
|
||||
* object representing a bookmarked item, as defined above.
|
||||
* @param onResult [optional]
|
||||
* Callback invoked for each created or updated bookmark. It gets
|
||||
* the bookmark object as argument.
|
||||
*
|
||||
* @return {Promise} resolved when the update is complete.
|
||||
* @resolves to the input object, updated with relevant information.
|
||||
* @rejects JavaScript exception.
|
||||
*
|
||||
* @note title is truncated to TITLE_LENGTH_MAX and URI is rejected if
|
||||
* greater than URI_LENGTH_MAX.
|
||||
* @resolves to a boolean indicating whether any new bookmark has been created.
|
||||
* @rejects JavaScript exception if it's not possible to update or create the
|
||||
* requested bookmark.
|
||||
* @throws if input is invalid.
|
||||
*/
|
||||
// XXX WIP XXX Will replace functionality from these methods:
|
||||
// long long insertBookmark(in long long aParentId, in nsIURI aURI, in long aIndex, in AUTF8String aTitle, [optional] in ACString aGUID);
|
||||
|
@ -133,9 +143,9 @@ let Bookmarks = Object.freeze({
|
|||
// void setItemLastModified(in long long aItemId, in PRTime aLastModified);
|
||||
// void changeBookmarkURI(in long long aItemId, in nsIURI aNewURI);
|
||||
// void setKeywordForBookmark(in long long aItemId, in AString aKeyword);
|
||||
update: Task.async(function* (info) {
|
||||
update: function (info, onResult=null) {
|
||||
throw new Error("Not yet implemented");
|
||||
}),
|
||||
},
|
||||
|
||||
/**
|
||||
* Removes a bookmarked item.
|
||||
|
@ -145,25 +155,30 @@ let Bookmarks = Object.freeze({
|
|||
* - guid: if set, only the corresponding item is removed.
|
||||
* - parentGuid: if it's set and is a folder, any children of that folder is
|
||||
* removed, but not the folder itself.
|
||||
* - URI: if set, any bookmark for that URI is removed.
|
||||
* If multiple of these properties are set, the method rejects.
|
||||
* - url: if set, any bookmark for that URL is removed.
|
||||
* If multiple of these properties are set, the method throws.
|
||||
*
|
||||
* Any other property is ignored, known properties may be overwritten.
|
||||
*
|
||||
* @param guidOrInfo
|
||||
* The globally unique identifier of the item to remove, or an
|
||||
* object representing it, as defined above.
|
||||
* @param onResult [optional]
|
||||
* Callback invoked for each removed bookmark. It gets the bookmark
|
||||
* object as argument.
|
||||
*
|
||||
* @return {Promise} resolved when the removal is complete.
|
||||
* @resolves to the removed object or an array of them.
|
||||
* @rejects JavaScript exception.
|
||||
* @resolves to a boolean indicating whether any object has been removed.
|
||||
* @rejects JavaScript exception if the provided guid or parentGuid don't
|
||||
* match any existing bookmark.
|
||||
* @throws if input is invalid.
|
||||
*/
|
||||
// XXX WIP XXX Will replace functionality from these methods:
|
||||
// removeItem(in long long aItemId);
|
||||
// removeFolderChildren(in long long aItemId);
|
||||
remove: Task.async(function* (guidOrInfo) {
|
||||
remove: function (guidOrInfo, onResult=null) {
|
||||
throw new Error("Not yet implemented");
|
||||
}),
|
||||
},
|
||||
|
||||
/**
|
||||
* Fetches information about a bookmarked item.
|
||||
|
@ -174,10 +189,10 @@ let Bookmarks = Object.freeze({
|
|||
* retrieves the item with the specified guid
|
||||
* - parentGuid and index
|
||||
* retrieves the item by its position
|
||||
* - URI
|
||||
* retrieves all items having the given URI.
|
||||
* - url
|
||||
* retrieves an array of items having the given URL.
|
||||
* - keyword
|
||||
* retrieves all items having the given keyword.
|
||||
* retrieves an array of items having the given keyword.
|
||||
*
|
||||
* Any other property is ignored. Known properties may be overwritten.
|
||||
*
|
||||
|
@ -190,6 +205,7 @@ let Bookmarks = Object.freeze({
|
|||
* an array of such objects. if no item is found, the returned
|
||||
* promise is resolved to null.
|
||||
* @rejects JavaScript exception.
|
||||
* @throws if input is invalid.
|
||||
*/
|
||||
// XXX WIP XXX Will replace functionality from these methods:
|
||||
// long long getIdForItemAt(in long long aParentId, in long aIndex);
|
||||
|
@ -205,16 +221,16 @@ let Bookmarks = Object.freeze({
|
|||
// AString getKeywordForURI(in nsIURI aURI);
|
||||
// AString getKeywordForBookmark(in long long aItemId);
|
||||
// nsIURI getURIForKeyword(in AString keyword);
|
||||
fetch: Task.async(function* (guidOrInfo) {
|
||||
fetch: function (guidOrInfo) {
|
||||
throw new Error("Not yet implemented");
|
||||
}),
|
||||
},
|
||||
|
||||
/**
|
||||
* Retrieves an object representation of a bookmarked item, along with all of
|
||||
* its descendants, if any.
|
||||
*
|
||||
* Each node in the tree is an object that extends
|
||||
* the item representation described above with some additional properties:
|
||||
* Each node in the tree is an object that extends the item representation
|
||||
* described above with some additional properties:
|
||||
*
|
||||
* - [deprecated] id (number)
|
||||
* the item's id. Defined only if aOptions.includeItemIds is set.
|
||||
|
@ -227,12 +243,12 @@ let Bookmarks = Object.freeze({
|
|||
* the number of items, including the root item itself, which are
|
||||
* represented in the resolved object.
|
||||
*
|
||||
* Bookmarked URIs may also have the following properties:
|
||||
* Bookmarked URLs may also have the following properties:
|
||||
* - tags (string)
|
||||
* csv string of the bookmark's tags, if any.
|
||||
* - charset (string)
|
||||
* the last known charset of the bookmark, if any.
|
||||
* - iconuri (string)
|
||||
* - iconurl (URL)
|
||||
* the bookmark's favicon URL, if any.
|
||||
*
|
||||
* Folders may also have the following properties:
|
||||
|
@ -266,12 +282,13 @@ let Bookmarks = Object.freeze({
|
|||
* bookmarks tree. if guid points to a non-existent item, the
|
||||
* returned promise is resolved to null.
|
||||
* @rejects JavaScript exception.
|
||||
* @throws if input is invalid.
|
||||
*/
|
||||
// XXX WIP XXX: will replace functionality for these methods:
|
||||
// PlacesUtils.promiseBookmarksTree()
|
||||
fetchTree: Task.async(function* (guid = "", options = {}) {
|
||||
fetchTree: function (guid = "", options = {}) {
|
||||
throw new Error("Not yet implemented");
|
||||
}),
|
||||
},
|
||||
|
||||
/**
|
||||
* Reorders contents of a folder based on a provided array of GUIDs.
|
||||
|
@ -286,10 +303,11 @@ let Bookmarks = Object.freeze({
|
|||
*
|
||||
* @return {Promise} resolved when reordering is complete.
|
||||
* @rejects JavaScript exception.
|
||||
* @throws if input is invalid.
|
||||
*/
|
||||
// XXX WIP XXX Will replace functionality from these methods:
|
||||
// void setItemIndex(in long long aItemId, in long aNewIndex);
|
||||
reorder: Task.async(function* (parentGuid, orderedChildrenGuids) {
|
||||
reorder: function (parentGuid, orderedChildrenGuids) {
|
||||
throw new Error("Not yet implemented");
|
||||
})
|
||||
}
|
||||
});
|
||||
|
|
|
@ -117,23 +117,26 @@ treechildren.autocomplete-treebody::-moz-tree-cell-text(selected) {
|
|||
color: MenuText;
|
||||
}
|
||||
|
||||
.ac-url-box {
|
||||
/* When setting a vertical margin here, half of that needs to be added
|
||||
.ac-title-box's translateY for when .ac-url-box is hidden (see below). */
|
||||
margin-top: 1px;
|
||||
}
|
||||
|
||||
.autocomplete-richlistitem[actiontype="keyword"] .ac-url-box,
|
||||
.autocomplete-richlistitem[actiontype="searchengine"] .ac-url-box,
|
||||
.autocomplete-richlistitem[actiontype="visiturl"] .ac-url-box,
|
||||
.autocomplete-richlistitem[type~="autofill"] .ac-url-box {
|
||||
display: none;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.autocomplete-richlistitem[actiontype="keyword"] .ac-title-box,
|
||||
.autocomplete-richlistitem[actiontype="searchengine"] .ac-title-box,
|
||||
.autocomplete-richlistitem[actiontype="visiturl"] .ac-title-box,
|
||||
.autocomplete-richlistitem[type~="autofill"] .ac-title-box {
|
||||
margin-top: 12px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.ac-url-box {
|
||||
margin-top: 1px;
|
||||
/* Center the title by moving it down by half of .ac-url-box's height,
|
||||
including vertical margins (if any). */
|
||||
transform: translateY(.5em);
|
||||
}
|
||||
|
||||
.ac-site-icon {
|
||||
|
|
|
@ -102,23 +102,26 @@ treechildren.autocomplete-treebody::-moz-tree-cell-text(selected) {
|
|||
padding: 5px 2px;
|
||||
}
|
||||
|
||||
.ac-url-box {
|
||||
/* When setting a vertical margin here, half of that needs to be added
|
||||
.ac-title-box's translateY for when .ac-url-box is hidden (see below). */
|
||||
margin-top: 1px;
|
||||
}
|
||||
|
||||
.autocomplete-richlistitem[actiontype="keyword"] .ac-url-box,
|
||||
.autocomplete-richlistitem[actiontype="searchengine"] .ac-url-box,
|
||||
.autocomplete-richlistitem[actiontype="visiturl"] .ac-url-box,
|
||||
.autocomplete-richlistitem[type~="autofill"] .ac-url-box {
|
||||
display: none;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.autocomplete-richlistitem[actiontype="keyword"] .ac-title-box,
|
||||
.autocomplete-richlistitem[actiontype="searchengine"] .ac-title-box,
|
||||
.autocomplete-richlistitem[actiontype="visiturl"] .ac-title-box,
|
||||
.autocomplete-richlistitem[type~="autofill"] .ac-title-box {
|
||||
margin-top: 12px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.ac-url-box {
|
||||
margin-top: 1px;
|
||||
/* Center the title by moving it down by half of .ac-url-box's height,
|
||||
including vertical margins (if any). */
|
||||
transform: translateY(.5em);
|
||||
}
|
||||
|
||||
.ac-site-icon {
|
||||
|
|
|
@ -130,27 +130,30 @@ treechildren.autocomplete-treebody::-moz-tree-cell-text(selected) {
|
|||
}
|
||||
%endif
|
||||
|
||||
.ac-title-box {
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.ac-url-box {
|
||||
/* When setting a vertical margin here, half of that needs to be added
|
||||
.ac-title-box's translateY for when .ac-url-box is hidden (see below). */
|
||||
margin: 1px 0 4px;
|
||||
}
|
||||
|
||||
.autocomplete-richlistitem[actiontype="keyword"] .ac-url-box,
|
||||
.autocomplete-richlistitem[actiontype="searchengine"] .ac-url-box,
|
||||
.autocomplete-richlistitem[actiontype="visiturl"] .ac-url-box,
|
||||
.autocomplete-richlistitem[type~="autofill"] .ac-url-box {
|
||||
display: none;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.autocomplete-richlistitem[actiontype="keyword"] .ac-title-box,
|
||||
.autocomplete-richlistitem[actiontype="searchengine"] .ac-title-box,
|
||||
.autocomplete-richlistitem[actiontype="visiturl"] .ac-title-box,
|
||||
.autocomplete-richlistitem[type~="autofill"] .ac-title-box {
|
||||
margin-top: 12px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.ac-title-box {
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.ac-url-box {
|
||||
margin: 1px 0 4px;
|
||||
/* Center the title by moving it down by half of .ac-url-box's height,
|
||||
including vertical margins (if any). */
|
||||
transform: translateY(calc(.5em + 2px));
|
||||
}
|
||||
|
||||
.ac-site-icon {
|
||||
|
|
Загрузка…
Ссылка в новой задаче