mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-13 18:27:35 +00:00
Bug 1369393 - Backout GV-based custom tabs, PWAs, and Tabs.java changes. r=me
This commit is contained in:
parent
881795c074
commit
093f070363
@ -1418,7 +1418,7 @@ public abstract class GeckoApp extends GeckoActivity
|
||||
"ToggleChrome:Show",
|
||||
null);
|
||||
|
||||
Tabs.getInstance().attachToContext(this, mLayerView, getAppEventDispatcher());
|
||||
Tabs.getInstance().attachToContext(this, mLayerView);
|
||||
Tabs.registerOnTabsChangedListener(this);
|
||||
|
||||
// Use global layout state change to kick off additional initialization
|
||||
@ -1512,7 +1512,7 @@ public abstract class GeckoApp extends GeckoActivity
|
||||
|
||||
// If we are doing a restore, send the parsed session data to Gecko.
|
||||
if (!mIsRestoringActivity) {
|
||||
getAppEventDispatcher().dispatch("Session:Restore", restoreMessage);
|
||||
EventDispatcher.getInstance().dispatch("Session:Restore", restoreMessage);
|
||||
}
|
||||
|
||||
// Make sure sessionstore.old is either updated or deleted as necessary.
|
||||
@ -2489,7 +2489,6 @@ public abstract class GeckoApp extends GeckoActivity
|
||||
super.onDestroy();
|
||||
|
||||
Tabs.unregisterOnTabsChangedListener(this);
|
||||
Tabs.getInstance().detachFromContext();
|
||||
|
||||
if (mShutdownOnDestroy) {
|
||||
GeckoApplication.shutdown(!mRestartOnShutdown ? null : new Intent(
|
||||
|
@ -182,7 +182,7 @@ class GlobalHistory {
|
||||
/* protected */ void checkVisited(final String uri) {
|
||||
final String storedURI = ReaderModeUtils.stripAboutReaderUrl(uri);
|
||||
|
||||
final NotifierRunnable runnable = new NotifierRunnable(GeckoAppShell.getApplicationContext());
|
||||
final NotifierRunnable runnable = new NotifierRunnable(GeckoAppShell.getContext());
|
||||
mHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
|
@ -101,7 +101,6 @@ public class Tabs implements BundleEventListener {
|
||||
private volatile boolean mInitialTabsAdded;
|
||||
|
||||
private Context mAppContext;
|
||||
private EventDispatcher mEventDispatcher;
|
||||
private LayerView mLayerView;
|
||||
private ContentObserver mBookmarksContentObserver;
|
||||
private PersistTabsRunnable mPersistTabsRunnable;
|
||||
@ -166,11 +165,18 @@ public class Tabs implements BundleEventListener {
|
||||
mPrivateClearColor = Color.RED;
|
||||
}
|
||||
|
||||
public synchronized void attachToContext(Context context, LayerView layerView, EventDispatcher eventDispatcher) {
|
||||
public synchronized void attachToContext(Context context, LayerView layerView) {
|
||||
final Context appContext = context.getApplicationContext();
|
||||
if (mAppContext == appContext) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mAppContext != null) {
|
||||
// This should never happen.
|
||||
Log.w(LOGTAG, "The application context has changed!");
|
||||
}
|
||||
|
||||
mAppContext = appContext;
|
||||
mEventDispatcher = eventDispatcher;
|
||||
mLayerView = layerView;
|
||||
mPrivateClearColor = ContextCompat.getColor(context, R.color.tabs_tray_grey_pressed);
|
||||
mAccountManager = AccountManager.get(appContext);
|
||||
@ -192,10 +198,6 @@ public class Tabs implements BundleEventListener {
|
||||
}
|
||||
}
|
||||
|
||||
public void detachFromContext() {
|
||||
mLayerView = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the tab count corresponding to the category and private state of the
|
||||
* selected tab.
|
||||
@ -330,7 +332,6 @@ public class Tabs implements BundleEventListener {
|
||||
// Pass a message to Gecko to update tab state in BrowserApp.
|
||||
final GeckoBundle data = new GeckoBundle(1);
|
||||
data.putInt("id", tab.getId());
|
||||
mEventDispatcher.dispatch("Tab:Selected", data);
|
||||
EventDispatcher.getInstance().dispatch("Tab:Selected", data);
|
||||
return tab;
|
||||
}
|
||||
@ -472,7 +473,7 @@ public class Tabs implements BundleEventListener {
|
||||
final GeckoBundle data = new GeckoBundle(2);
|
||||
data.putInt("tabId", tabId);
|
||||
data.putBoolean("showUndoToast", showUndoToast);
|
||||
mEventDispatcher.dispatch("Tab:Closed", data);
|
||||
EventDispatcher.getInstance().dispatch("Tab:Closed", data);
|
||||
}
|
||||
|
||||
/** Return the tab that will be selected by default after this one is closed */
|
||||
@ -1082,7 +1083,7 @@ public class Tabs implements BundleEventListener {
|
||||
}
|
||||
}
|
||||
|
||||
mEventDispatcher.dispatch("Tab:Load", data);
|
||||
EventDispatcher.getInstance().dispatch("Tab:Load", data);
|
||||
|
||||
if (tabToSelect == null) {
|
||||
return null;
|
||||
@ -1276,7 +1277,7 @@ public class Tabs implements BundleEventListener {
|
||||
data.putInt("fromPosition", fromPosition);
|
||||
data.putInt("toTabId", toTabId);
|
||||
data.putInt("toPosition", toPosition);
|
||||
mEventDispatcher.dispatch("Tab:Move", data);
|
||||
EventDispatcher.getInstance().dispatch("Tab:Move", data);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -30,7 +30,6 @@ import android.widget.ImageButton;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.mozilla.gecko.GeckoView;
|
||||
import org.mozilla.gecko.R;
|
||||
import org.mozilla.gecko.SiteIdentity;
|
||||
import org.mozilla.gecko.Tab;
|
||||
@ -109,24 +108,25 @@ public class ActionBarPresenter {
|
||||
* @param url Url String to display
|
||||
*/
|
||||
public void displayUrlOnly(@NonNull final String url) {
|
||||
updateCustomView(null, url, GeckoView.ProgressListener.STATE_IS_INSECURE);
|
||||
updateCustomView(null, null, url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update appearance of CustomView of ActionBar
|
||||
* Update appearance of CustomView of ActionBar.
|
||||
*
|
||||
* @param title Title for current website. Could be null if don't want to show title.
|
||||
* @param url URL for current website. At least Custom will show this url.
|
||||
* @param securityStatus Security status, possible values given in GeckoView.ProgressListener
|
||||
* @param tab a Tab instance of current web page to provide information to render ActionBar.
|
||||
*/
|
||||
public void update(final String title, final String url, final int securityStatus) {
|
||||
public void update(@NonNull final Tab tab) {
|
||||
final String title = tab.getTitle();
|
||||
final String url = tab.getBaseDomain();
|
||||
|
||||
// Do not update CustomView immediately. If this method be invoked rapidly several times,
|
||||
// only apply last one.
|
||||
mHandler.removeCallbacks(mUpdateAction);
|
||||
mUpdateAction = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
updateCustomView(title, url, securityStatus);
|
||||
updateCustomView(tab.getSiteIdentity(), title, url);
|
||||
}
|
||||
};
|
||||
mHandler.postDelayed(mUpdateAction, CUSTOM_VIEW_UPDATE_DELAY);
|
||||
@ -220,15 +220,25 @@ public class ActionBarPresenter {
|
||||
* @param url URL for current website. At least Custom will show this url.
|
||||
*/
|
||||
@UiThread
|
||||
private void updateCustomView(final String title, final String url, final int securityStatus) {
|
||||
if (securityStatus == GeckoView.ProgressListener.STATE_IS_SECURE) {
|
||||
mIconView.setVisibility(View.VISIBLE);
|
||||
mIconView.setImageLevel(SecurityModeUtil.Mode.LOCK_SECURE.ordinal());
|
||||
// Lock-Secure is special case. Keep its original green color.
|
||||
DrawableCompat.setTintList(mIconView.getDrawable(), null);
|
||||
} else {
|
||||
private void updateCustomView(@Nullable SiteIdentity identity,
|
||||
@Nullable String title,
|
||||
@NonNull String url) {
|
||||
// update site-info icon
|
||||
if (identity == null) {
|
||||
mIconView.setVisibility(View.INVISIBLE);
|
||||
DrawableCompat.setTint(mIconView.getDrawable(), mTextPrimaryColor);
|
||||
} else {
|
||||
final SecurityModeUtil.Mode mode = SecurityModeUtil.resolve(identity);
|
||||
mIconView.setVisibility(View.VISIBLE);
|
||||
mIconView.setImageLevel(mode.ordinal());
|
||||
mIdentityPopup.setSiteIdentity(identity);
|
||||
|
||||
if (mode == SecurityModeUtil.Mode.LOCK_SECURE) {
|
||||
// Lock-Secure is special case. Keep its original green color.
|
||||
DrawableCompat.setTintList(mIconView.getDrawable(), null);
|
||||
} else {
|
||||
// Icon use same color as TextView.
|
||||
DrawableCompat.setTint(mIconView.getDrawable(), mTextPrimaryColor);
|
||||
}
|
||||
}
|
||||
|
||||
// If no title to use, use Url as title
|
||||
|
@ -20,7 +20,7 @@ import android.support.annotation.NonNull;
|
||||
import android.support.design.widget.Snackbar;
|
||||
import android.support.v4.util.SparseArrayCompat;
|
||||
import android.support.v7.app.ActionBar;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.support.v7.view.ActionMode;
|
||||
import android.support.v7.widget.Toolbar;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
@ -28,14 +28,17 @@ import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.ProgressBar;
|
||||
|
||||
import org.mozilla.gecko.EventDispatcher;
|
||||
import org.mozilla.gecko.GeckoView;
|
||||
import org.mozilla.gecko.GeckoViewSettings;
|
||||
import org.mozilla.gecko.R;
|
||||
import org.mozilla.gecko.SingleTabActivity;
|
||||
import org.mozilla.gecko.SnackbarBuilder;
|
||||
import org.mozilla.gecko.Tab;
|
||||
import org.mozilla.gecko.Tabs;
|
||||
import org.mozilla.gecko.Telemetry;
|
||||
import org.mozilla.gecko.TelemetryContract;
|
||||
import org.mozilla.gecko.gfx.DynamicToolbarAnimator.PinReason;
|
||||
import org.mozilla.gecko.menu.GeckoMenu;
|
||||
import org.mozilla.gecko.menu.GeckoMenuInflater;
|
||||
import org.mozilla.gecko.mozglue.SafeIntent;
|
||||
@ -43,15 +46,14 @@ import org.mozilla.gecko.util.Clipboard;
|
||||
import org.mozilla.gecko.util.ColorUtil;
|
||||
import org.mozilla.gecko.util.GeckoBundle;
|
||||
import org.mozilla.gecko.util.IntentUtils;
|
||||
import org.mozilla.gecko.widget.ActionModePresenter;
|
||||
import org.mozilla.gecko.widget.GeckoPopupMenu;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class CustomTabsActivity extends AppCompatActivity
|
||||
implements GeckoMenu.Callback,
|
||||
GeckoView.ContentListener,
|
||||
GeckoView.NavigationListener,
|
||||
GeckoView.ProgressListener {
|
||||
import static org.mozilla.gecko.Tabs.TabEvents;
|
||||
|
||||
public class CustomTabsActivity extends SingleTabActivity implements Tabs.OnTabsChangedListener {
|
||||
|
||||
private static final String LOGTAG = "CustomTabsActivity";
|
||||
|
||||
@ -59,30 +61,21 @@ public class CustomTabsActivity extends AppCompatActivity
|
||||
private GeckoPopupMenu popupMenu;
|
||||
private View doorhangerOverlay;
|
||||
private ActionBarPresenter actionBarPresenter;
|
||||
private ProgressBar mProgressView;
|
||||
// A state to indicate whether this activity is finishing with customize animation
|
||||
private boolean usingCustomAnimation = false;
|
||||
|
||||
private MenuItem menuItemControl;
|
||||
|
||||
private GeckoView mGeckoView;
|
||||
|
||||
private boolean mCanGoBack = false;
|
||||
private boolean mCanGoForward = false;
|
||||
private boolean mCanStop = false;
|
||||
private String mCurrentUrl;
|
||||
private String mCurrentTitle;
|
||||
private int mSecurityStatus = GeckoView.ProgressListener.STATE_IS_INSECURE;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setContentView(R.layout.customtabs_activity);
|
||||
|
||||
final SafeIntent intent = new SafeIntent(getIntent());
|
||||
|
||||
doorhangerOverlay = findViewById(R.id.custom_tabs_doorhanger_overlay);
|
||||
|
||||
mProgressView = (ProgressBar) findViewById(R.id.page_progress);
|
||||
final Toolbar toolbar = (Toolbar) findViewById(R.id.actionbar);
|
||||
setSupportActionBar(toolbar);
|
||||
final ActionBar actionBar = getSupportActionBar();
|
||||
@ -92,22 +85,26 @@ public class CustomTabsActivity extends AppCompatActivity
|
||||
actionBarPresenter.displayUrlOnly(intent.getDataString());
|
||||
actionBarPresenter.setBackgroundColor(IntentUtil.getToolbarColor(intent), getWindow());
|
||||
actionBarPresenter.setTextLongClickListener(new UrlCopyListener());
|
||||
}
|
||||
|
||||
mGeckoView = (GeckoView) findViewById(R.id.gecko_view);
|
||||
@Override
|
||||
protected void onTabOpenFromIntent(Tab tab) {
|
||||
super.onTabOpenFromIntent(tab);
|
||||
|
||||
mGeckoView.setNavigationListener(this);
|
||||
mGeckoView.setProgressListener(this);
|
||||
mGeckoView.setContentListener(this);
|
||||
final String host = getReferrerHost();
|
||||
recordCustomTabUsage(host);
|
||||
sendTelemetry();
|
||||
}
|
||||
|
||||
final GeckoViewSettings settings = mGeckoView.getSettings();
|
||||
settings.setBoolean(GeckoViewSettings.USE_MULTIPROCESS, false);
|
||||
@Override
|
||||
protected void onTabSelectFromIntent(Tab tab) {
|
||||
super.onTabSelectFromIntent(tab);
|
||||
|
||||
if (intent != null && !TextUtils.isEmpty(intent.getDataString())) {
|
||||
mGeckoView.loadUri(intent.getDataString());
|
||||
} else {
|
||||
Log.w(LOGTAG, "No intend found for custom tab");
|
||||
finish();
|
||||
}
|
||||
// We already listen for SELECTED events, but if the activity has been destroyed and
|
||||
// subsequently recreated without a different tab having been selected in Gecko in the
|
||||
// meantime, our startup won't trigger a SELECTED event because the selected tab in Gecko
|
||||
// doesn't actually change.
|
||||
actionBarPresenter.update(tab);
|
||||
}
|
||||
|
||||
private void sendTelemetry() {
|
||||
@ -157,6 +154,13 @@ public class CustomTabsActivity extends AppCompatActivity
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDone() {
|
||||
// We're most probably running within a foreign app's task, so we have no choice what to
|
||||
// call here if we want to allow the user to return to that task's previous activity.
|
||||
finish();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finish() {
|
||||
super.finish();
|
||||
@ -172,12 +176,63 @@ public class CustomTabsActivity extends AppCompatActivity
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
if (mCanGoBack) {
|
||||
mGeckoView.goBack();
|
||||
} else {
|
||||
finish();
|
||||
protected int getNewTabFlags() {
|
||||
return Tabs.LOADURL_CUSTOMTAB | super.getNewTabFlags();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLayout() {
|
||||
return R.layout.customtabs_activity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getDoorhangerOverlay() {
|
||||
return doorhangerOverlay;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTabChanged(Tab tab, TabEvents msg, String data) {
|
||||
super.onTabChanged(tab, msg, data);
|
||||
|
||||
if (!Tabs.getInstance().isSelectedTab(tab) ||
|
||||
tab.getType() != Tab.TabType.CUSTOMTAB) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (msg == TabEvents.START
|
||||
|| msg == TabEvents.STOP
|
||||
|| msg == TabEvents.ADDED
|
||||
|| msg == TabEvents.LOAD_ERROR
|
||||
|| msg == TabEvents.LOADED
|
||||
|| msg == TabEvents.LOCATION_CHANGE
|
||||
|| msg == TabEvents.SELECTED) {
|
||||
|
||||
updateProgress((tab.getState() == Tab.STATE_LOADING),
|
||||
tab.getLoadProgress());
|
||||
}
|
||||
|
||||
if (msg == TabEvents.LOCATION_CHANGE
|
||||
|| msg == TabEvents.SECURITY_CHANGE
|
||||
|| msg == TabEvents.TITLE
|
||||
|| msg == TabEvents.SELECTED) {
|
||||
actionBarPresenter.update(tab);
|
||||
}
|
||||
|
||||
updateMenuItemForward();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
mLayerView.getDynamicToolbarAnimator().setPinned(true, PinReason.CUSTOM_TAB);
|
||||
actionBarPresenter.onResume();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
mLayerView.getDynamicToolbarAnimator().setPinned(false, PinReason.CUSTOM_TAB);
|
||||
actionBarPresenter.onPause();
|
||||
}
|
||||
|
||||
// Usually should use onCreateOptionsMenu() to initialize menu items. But GeckoApp overwrite
|
||||
@ -185,7 +240,7 @@ public class CustomTabsActivity extends AppCompatActivity
|
||||
// and this.onPrepareOptionsMenu() are different instances - GeckoApp.onCreatePanelMenu() changed it.
|
||||
// CustomTabsActivity only use standard menu in ActionBar, so initialize menu here.
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(final Menu menu) {
|
||||
public boolean onCreatePanelMenu(final int id, final Menu menu) {
|
||||
|
||||
// if 3rd-party app asks to add an action button
|
||||
SafeIntent intent = new SafeIntent(getIntent());
|
||||
@ -220,16 +275,6 @@ public class CustomTabsActivity extends AppCompatActivity
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onMenuItemClick(MenuItem item) {
|
||||
return onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onMenuItemLongClick(MenuItem item) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
@ -272,11 +317,34 @@ public class CustomTabsActivity extends AppCompatActivity
|
||||
performPendingIntent(intent);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ActionModePresenter getTextSelectPresenter() {
|
||||
return new ActionModePresenter() {
|
||||
private ActionMode mMode;
|
||||
|
||||
@Override
|
||||
public void startActionMode(ActionMode.Callback callback) {
|
||||
mMode = startSupportActionMode(callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endActionMode() {
|
||||
if (mMode != null) {
|
||||
mMode.finish();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void bindNavigationCallback(@NonNull final Toolbar toolbar) {
|
||||
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
finish();
|
||||
onDone();
|
||||
final Tabs tabs = Tabs.getInstance();
|
||||
final Tab tab = tabs.getSelectedTab();
|
||||
mSuppressActivitySwitch = true;
|
||||
tabs.closeTab(tab);
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -284,7 +352,8 @@ public class CustomTabsActivity extends AppCompatActivity
|
||||
private void performPendingIntent(@NonNull PendingIntent pendingIntent) {
|
||||
// bug 1337771: If intent-creator haven't set data url, call send() directly won't work.
|
||||
final Intent additional = new Intent();
|
||||
additional.setData(Uri.parse(mCurrentUrl));
|
||||
final Tab tab = Tabs.getInstance().getSelectedTab();
|
||||
additional.setData(Uri.parse(tab.getURL()));
|
||||
try {
|
||||
pendingIntent.send(this, 0, additional);
|
||||
} catch (PendingIntent.CanceledException e) {
|
||||
@ -366,45 +435,49 @@ public class CustomTabsActivity extends AppCompatActivity
|
||||
}
|
||||
|
||||
final MenuItem forwardMenuItem = popupMenu.getMenu().findItem(R.id.custom_tabs_menu_forward);
|
||||
forwardMenuItem.setEnabled(mCanGoForward);
|
||||
final Tab tab = Tabs.getInstance().getSelectedTab();
|
||||
final boolean enabled = (tab != null && tab.canDoForward());
|
||||
forwardMenuItem.setEnabled(enabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update loading status of current page
|
||||
* Update loading progress of current page
|
||||
*
|
||||
* @param isLoading to indicate whether ProgressBar should be visible or not
|
||||
* @param progress value of loading progress in percent, should be 0 - 100.
|
||||
*/
|
||||
private void updateCanStop() {
|
||||
private void updateProgress(final boolean isLoading, final int progress) {
|
||||
if (isLoading) {
|
||||
mProgressView.setVisibility(View.VISIBLE);
|
||||
mProgressView.setProgress(progress);
|
||||
} else {
|
||||
mProgressView.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
if (menuItemControl != null) {
|
||||
Drawable icon = menuItemControl.getIcon();
|
||||
if (mCanStop) {
|
||||
icon.setLevel(0);
|
||||
} else {
|
||||
icon.setLevel(100);
|
||||
}
|
||||
icon.setLevel(progress);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the state of the action bar
|
||||
*/
|
||||
private void updateActionBar() {
|
||||
actionBarPresenter.update(mCurrentTitle, mCurrentUrl, mSecurityStatus);
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this method to reload page, or stop page loading if progress not complete yet.
|
||||
*/
|
||||
private void onLoadingControlClicked() {
|
||||
if (mCanStop) {
|
||||
// TODO: enable this after implementing GeckoView.stop()
|
||||
//mGeckoView.stop();
|
||||
} else {
|
||||
mGeckoView.reload();
|
||||
final Tab tab = Tabs.getInstance().getSelectedTab();
|
||||
if (tab != null) {
|
||||
if (tab.getLoadProgress() == Tab.LOAD_PROGRESS_STOP) {
|
||||
tab.doReload(true);
|
||||
} else {
|
||||
tab.doStop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void onForwardClicked() {
|
||||
if (mCanGoForward) {
|
||||
mGeckoView.goForward();
|
||||
final Tab tab = Tabs.getInstance().getSelectedTab();
|
||||
if ((tab != null) && tab.canDoForward()) {
|
||||
tab.doForward();
|
||||
}
|
||||
}
|
||||
|
||||
@ -412,11 +485,15 @@ public class CustomTabsActivity extends AppCompatActivity
|
||||
* Callback for Open-in menu item.
|
||||
*/
|
||||
private void onOpenInClicked() {
|
||||
final Intent intent = new Intent();
|
||||
intent.setData(Uri.parse(mCurrentUrl));
|
||||
intent.setAction(Intent.ACTION_VIEW);
|
||||
startActivity(intent);
|
||||
finish();
|
||||
final Tab tab = Tabs.getInstance().getSelectedTab();
|
||||
if (tab != null) {
|
||||
// To launch default browser with url of current tab.
|
||||
final Intent intent = new Intent();
|
||||
intent.setData(Uri.parse(tab.getURL()));
|
||||
intent.setAction(Intent.ACTION_VIEW);
|
||||
startActivity(intent);
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
private void onActionButtonClicked() {
|
||||
@ -430,10 +507,12 @@ public class CustomTabsActivity extends AppCompatActivity
|
||||
* Callback for Share menu item.
|
||||
*/
|
||||
private void onShareClicked() {
|
||||
if (!TextUtils.isEmpty(mCurrentUrl)) {
|
||||
final String url = Tabs.getInstance().getSelectedTab().getURL();
|
||||
|
||||
if (!TextUtils.isEmpty(url)) {
|
||||
Intent shareIntent = new Intent(Intent.ACTION_SEND);
|
||||
shareIntent.setType("text/plain");
|
||||
shareIntent.putExtra(Intent.EXTRA_TEXT, mCurrentUrl);
|
||||
shareIntent.putExtra(Intent.EXTRA_TEXT, url);
|
||||
|
||||
Intent chooserIntent = Intent.createChooser(shareIntent, getString(R.string.share_title));
|
||||
chooserIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
@ -447,8 +526,9 @@ public class CustomTabsActivity extends AppCompatActivity
|
||||
private class UrlCopyListener implements View.OnLongClickListener {
|
||||
@Override
|
||||
public boolean onLongClick(View v) {
|
||||
if (!TextUtils.isEmpty(mCurrentUrl)) {
|
||||
Clipboard.setText(mCurrentUrl);
|
||||
final String url = Tabs.getInstance().getSelectedTab().getURL();
|
||||
if (!TextUtils.isEmpty(url)) {
|
||||
Clipboard.setText(url);
|
||||
SnackbarBuilder.builder(CustomTabsActivity.this)
|
||||
.message(R.string.custom_tabs_hint_url_copy)
|
||||
.duration(Snackbar.LENGTH_SHORT)
|
||||
@ -474,59 +554,4 @@ public class CustomTabsActivity extends AppCompatActivity
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/* GeckoView.NavigationListener */
|
||||
@Override
|
||||
public void onLocationChange(GeckoView view, String url) {
|
||||
mCurrentUrl = url;
|
||||
updateActionBar();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCanGoBack(GeckoView view, boolean canGoBack) {
|
||||
mCanGoBack = canGoBack;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCanGoForward(GeckoView view, boolean canGoForward) {
|
||||
mCanGoForward = canGoForward;
|
||||
updateMenuItemForward();
|
||||
}
|
||||
|
||||
/* GeckoView.ProgressListener */
|
||||
@Override
|
||||
public void onPageStart(GeckoView view, String url) {
|
||||
mCurrentUrl = url;
|
||||
mCanStop = true;
|
||||
updateActionBar();
|
||||
updateCanStop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageStop(GeckoView view, boolean success) {
|
||||
mCanStop = false;
|
||||
updateCanStop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSecurityChange(GeckoView view, int status) {
|
||||
if ((status & STATE_IS_INSECURE) != 0) {
|
||||
mSecurityStatus = STATE_IS_INSECURE;
|
||||
} else if ((status & STATE_IS_BROKEN) != 0) {
|
||||
mSecurityStatus = STATE_IS_BROKEN;
|
||||
} else if ((status & STATE_IS_SECURE) != 0) {
|
||||
mSecurityStatus = STATE_IS_SECURE;
|
||||
}
|
||||
updateActionBar();
|
||||
}
|
||||
|
||||
/* GeckoView.ContentListener */
|
||||
@Override
|
||||
public void onTitleChange(GeckoView view, String title) {
|
||||
mCurrentTitle = title;
|
||||
updateActionBar();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFullScreen(GeckoView view, boolean fullScreen) {}
|
||||
}
|
||||
|
@ -7,17 +7,15 @@ package org.mozilla.gecko.webapps;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Bitmap;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.support.v7.app.ActionBar;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.support.v7.view.ActionMode;
|
||||
import android.support.v7.widget.Toolbar;
|
||||
import android.support.v7.app.ActionBar;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
@ -32,8 +30,6 @@ import org.json.JSONException;
|
||||
import org.mozilla.gecko.AppConstants;
|
||||
import org.mozilla.gecko.EventDispatcher;
|
||||
import org.mozilla.gecko.GeckoAppShell;
|
||||
import org.mozilla.gecko.GeckoView;
|
||||
import org.mozilla.gecko.GeckoViewSettings;
|
||||
import org.mozilla.gecko.SingleTabActivity;
|
||||
import org.mozilla.gecko.Telemetry;
|
||||
import org.mozilla.gecko.TelemetryContract;
|
||||
@ -52,22 +48,20 @@ import org.mozilla.gecko.widget.AnchoredPopup;
|
||||
|
||||
import static org.mozilla.gecko.Tabs.TabEvents;
|
||||
|
||||
public class WebAppActivity extends AppCompatActivity
|
||||
implements GeckoView.NavigationListener {
|
||||
public class WebAppActivity extends SingleTabActivity {
|
||||
private static final String LOGTAG = "WebAppActivity";
|
||||
|
||||
public static final String MANIFEST_PATH = "MANIFEST_PATH";
|
||||
private static final String SAVED_INTENT = "savedIntent";
|
||||
|
||||
private TextView mUrlView;
|
||||
private GeckoView mGeckoView;
|
||||
private View doorhangerOverlay;
|
||||
|
||||
private Uri mScope;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
if ((getIntent().getFlags() & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) != 0 &&
|
||||
savedInstanceState != null) {
|
||||
savedInstanceState != null) {
|
||||
// Even though we're a single task activity, Android's task switcher has the
|
||||
// annoying habit of never updating its stored intent after our initial creation,
|
||||
// even if we've been subsequently started with a new intent.
|
||||
@ -81,33 +75,73 @@ public class WebAppActivity extends AppCompatActivity
|
||||
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setContentView(R.layout.customtabs_activity);
|
||||
|
||||
final Toolbar toolbar = (Toolbar) findViewById(R.id.actionbar);
|
||||
setSupportActionBar(toolbar);
|
||||
|
||||
final ProgressBar progressBar = (ProgressBar) findViewById(R.id.page_progress);
|
||||
progressBar.setVisibility(View.GONE);
|
||||
|
||||
final ActionBar actionBar = getSupportActionBar();
|
||||
actionBar.setCustomView(R.layout.webapps_action_bar_custom_view);
|
||||
actionBar.setDisplayShowCustomEnabled(true);
|
||||
actionBar.setDisplayShowTitleEnabled(false);
|
||||
actionBar.hide();
|
||||
|
||||
doorhangerOverlay = findViewById(R.id.custom_tabs_doorhanger_overlay);
|
||||
|
||||
final View customView = actionBar.getCustomView();
|
||||
mUrlView = (TextView) customView.findViewById(R.id.webapps_action_bar_url);
|
||||
|
||||
mGeckoView = (GeckoView) findViewById(R.id.gecko_view);
|
||||
EventDispatcher.getInstance().registerUiThreadListener(this,
|
||||
"Website:AppEntered",
|
||||
"Website:AppLeft",
|
||||
null);
|
||||
}
|
||||
|
||||
mGeckoView.setNavigationListener(this);
|
||||
@Override
|
||||
public View getDoorhangerOverlay() {
|
||||
return doorhangerOverlay;
|
||||
}
|
||||
|
||||
final GeckoViewSettings settings = mGeckoView.getSettings();
|
||||
settings.setBoolean(GeckoViewSettings.USE_MULTIPROCESS, false);
|
||||
@Override
|
||||
public int getLayout() {
|
||||
return R.layout.customtabs_activity;
|
||||
}
|
||||
|
||||
final Uri u = getIntent().getData();
|
||||
if (u != null) {
|
||||
mGeckoView.loadUri(u.toString());
|
||||
@Override
|
||||
public void handleMessage(final String event, final GeckoBundle message,
|
||||
final EventCallback callback) {
|
||||
super.handleMessage(event, message, callback);
|
||||
|
||||
if (message == null ||
|
||||
!message.containsKey("tabId") || message.getInt("tabId") != mLastSelectedTabId) {
|
||||
return;
|
||||
}
|
||||
|
||||
loadManifest(getIntent().getStringExtra(MANIFEST_PATH));
|
||||
switch (event) {
|
||||
case "Website:AppEntered":
|
||||
getSupportActionBar().hide();
|
||||
break;
|
||||
|
||||
case "Website:AppLeft":
|
||||
getSupportActionBar().show();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTabChanged(Tab tab, Tabs.TabEvents msg, String data) {
|
||||
super.onTabChanged(tab, msg, data);
|
||||
|
||||
if (tab == null || !Tabs.getInstance().isSelectedTab(tab) ||
|
||||
tab.getType() != Tab.TabType.WEBAPP) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (msg == TabEvents.LOCATION_CHANGE ||
|
||||
msg == TabEvents.SELECTED) {
|
||||
mUrlView.setText(tab.getURL());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -117,6 +151,75 @@ public class WebAppActivity extends AppCompatActivity
|
||||
outState.putParcelable(SAVED_INTENT, getIntent());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
EventDispatcher.getInstance().unregisterUiThreadListener(this,
|
||||
"Website:AppEntered",
|
||||
"Website:AppLeft",
|
||||
null);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getNewTabFlags() {
|
||||
return Tabs.LOADURL_WEBAPP | super.getNewTabFlags();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onTabOpenFromIntent(Tab tab) {
|
||||
super.onTabOpenFromIntent(tab);
|
||||
Telemetry.sendUIEvent(TelemetryContract.Event.LOAD_URL, TelemetryContract.Method.INTENT, "webapp");
|
||||
loadManifest(tab.getManifestPath());
|
||||
}
|
||||
|
||||
/**
|
||||
* In case this activity and its tab are reused (the user has opened
|
||||
* > 10 current web apps), we check that app launched is still within
|
||||
* the same host as the intent has set.
|
||||
* If it isn't, we reload the intent URL.
|
||||
*/
|
||||
@Override
|
||||
protected void onTabSelectFromIntent(Tab tab) {
|
||||
super.onTabSelectFromIntent(tab);
|
||||
|
||||
SafeIntent intent = new SafeIntent(getIntent());
|
||||
|
||||
final String launchUrl = intent.getDataString();
|
||||
final String currentUrl = tab.getURL();
|
||||
final boolean isSameDomain = Uri.parse(currentUrl).getHost()
|
||||
.equals(Uri.parse(launchUrl).getHost());
|
||||
|
||||
final String manifestPath;
|
||||
if (!isSameDomain) {
|
||||
Telemetry.sendUIEvent(TelemetryContract.Event.LOAD_URL, TelemetryContract.Method.INTENT, "webapp");
|
||||
manifestPath = intent.getStringExtra(MANIFEST_PATH);
|
||||
tab.setManifestUrl(manifestPath);
|
||||
Tabs.getInstance().loadUrl(launchUrl);
|
||||
} else {
|
||||
manifestPath = tab.getManifestPath();
|
||||
}
|
||||
loadManifest(manifestPath);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ActionModePresenter getTextSelectPresenter() {
|
||||
return new ActionModePresenter() {
|
||||
private ActionMode mMode;
|
||||
|
||||
@Override
|
||||
public void startActionMode(ActionMode.Callback callback) {
|
||||
mMode = startSupportActionMode(callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endActionMode() {
|
||||
if (mMode != null) {
|
||||
mMode.finish();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void loadManifest(String manifestPath) {
|
||||
if (TextUtils.isEmpty(manifestPath)) {
|
||||
Log.e(LOGTAG, "Missing manifest");
|
||||
@ -134,7 +237,6 @@ public class WebAppActivity extends AppCompatActivity
|
||||
final Integer color = readColorFromManifest(manifestField);
|
||||
final String name = readNameFromManifest(manifestField);
|
||||
final Bitmap icon = readIconFromManifest(manifest);
|
||||
mScope = readScopeFromManifest(manifest, manifestPath);
|
||||
final ActivityManager.TaskDescription taskDescription = (color == null)
|
||||
? new ActivityManager.TaskDescription(name, icon)
|
||||
: new ActivityManager.TaskDescription(name, icon, color);
|
||||
@ -180,76 +282,10 @@ public class WebAppActivity extends AppCompatActivity
|
||||
return null;
|
||||
}
|
||||
final LoadFaviconResult loadIconResult = FaviconDecoder
|
||||
.decodeDataURI(this, iconStr);
|
||||
.decodeDataURI(getContext(), iconStr);
|
||||
if (loadIconResult == null) {
|
||||
return null;
|
||||
}
|
||||
return loadIconResult.getBestBitmap(GeckoAppShell.getPreferredIconSize());
|
||||
}
|
||||
|
||||
private Uri readScopeFromManifest(JSONObject manifest, String manifestPath) {
|
||||
final String scopeStr = manifest.optString("scope", null);
|
||||
if (scopeStr == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Uri res = Uri.parse(scopeStr);
|
||||
if (res.isRelative()) {
|
||||
// TODO: Handle this more correctly.
|
||||
return null;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
private boolean isInScope(String url) {
|
||||
if (mScope == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
final Uri uri = Uri.parse(url);
|
||||
|
||||
if (!uri.getScheme().equals(mScope.getScheme())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!uri.getHost().equals(mScope.getHost())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final List<String> scopeSegments = mScope.getPathSegments();
|
||||
final List<String> urlSegments = uri.getPathSegments();
|
||||
|
||||
if (scopeSegments.size() > urlSegments.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < scopeSegments.size(); i++) {
|
||||
if (!scopeSegments.get(i).equals(urlSegments.get(i))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* GeckoView.NavigationListener */
|
||||
@Override
|
||||
public void onLocationChange(GeckoView view, String url) {
|
||||
if (isInScope(url)) {
|
||||
getSupportActionBar().hide();
|
||||
} else {
|
||||
getSupportActionBar().show();
|
||||
}
|
||||
|
||||
mUrlView.setText(url);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCanGoBack(GeckoView view, boolean canGoBack) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCanGoForward(GeckoView view, boolean canGoForward) {
|
||||
}
|
||||
}
|
||||
|
@ -12,6 +12,11 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<!--
|
||||
This layout is quite complex because GeckoApp accesses all view groups
|
||||
in this tree. In a perfect world this should just include a GeckoView.
|
||||
-->
|
||||
|
||||
<android.support.v7.widget.Toolbar
|
||||
android:id="@id/actionbar"
|
||||
android:layout_width="match_parent"
|
||||
@ -20,18 +25,48 @@
|
||||
android:background="@color/text_and_tabs_tray_grey"
|
||||
app:layout_scrollFlags="scroll|enterAlways"/>
|
||||
|
||||
<org.mozilla.gecko.GeckoView
|
||||
android:id="@+id/gecko_view"
|
||||
android:layout_width="fill_parent"
|
||||
<view class="org.mozilla.gecko.GeckoApp$MainLayout"
|
||||
android:id="@+id/main_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_below="@id/actionbar"
|
||||
android:layout_height="match_parent"
|
||||
android:scrollbars="none"/>
|
||||
android:background="@android:color/transparent">
|
||||
|
||||
<RelativeLayout android:id="@+id/gecko_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_below="@+id/tablet_tab_strip"
|
||||
android:layout_above="@+id/find_in_page">
|
||||
|
||||
<fragment class="org.mozilla.gecko.GeckoViewFragment"
|
||||
android:id="@+id/layer_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:scrollbars="none"/>
|
||||
|
||||
<org.mozilla.gecko.FormAssistPopup android:id="@+id/form_assist_popup"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:visibility="gone"/>
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
</view>
|
||||
|
||||
<ProgressBar
|
||||
android:id="@id/page_progress"
|
||||
style="@style/Base.Widget.AppCompat.ProgressBar.Horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="4dp"
|
||||
android:layout_alignTop="@id/main_layout"
|
||||
android:background="@drawable/url_bar_bg"
|
||||
android:progressDrawable="@drawable/progressbar"
|
||||
tools:progress="70"/>
|
||||
|
||||
<View android:id="@+id/custom_tabs_doorhanger_overlay"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@color/dark_transparent_overlay"
|
||||
android:alpha="0"
|
||||
android:layerType="hardware"/>
|
||||
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@color/dark_transparent_overlay"
|
||||
android:alpha="0"
|
||||
android:layerType="hardware"/>
|
||||
</RelativeLayout>
|
@ -87,7 +87,7 @@ var FindHelper = {
|
||||
this._initialViewport = JSON.stringify(this._targetTab.getViewport());
|
||||
this._viewportChanged = false;
|
||||
|
||||
WindowEventDispatcher.registerListener(this, [
|
||||
GlobalEventDispatcher.registerListener(this, [
|
||||
"Tab:Selected",
|
||||
]);
|
||||
},
|
||||
@ -109,7 +109,7 @@ var FindHelper = {
|
||||
this._initialViewport = null;
|
||||
this._viewportChanged = false;
|
||||
|
||||
WindowEventDispatcher.unregisterListener(this, [
|
||||
GlobalEventDispatcher.unregisterListener(this, [
|
||||
"Tab:Selected",
|
||||
]);
|
||||
},
|
||||
|
@ -389,15 +389,11 @@ var BrowserApp = {
|
||||
|
||||
Services.androidBridge.browserApp = this;
|
||||
|
||||
WindowEventDispatcher.registerListener(this, [
|
||||
"Session:Restore",
|
||||
GlobalEventDispatcher.registerListener(this, [
|
||||
"Tab:Load",
|
||||
"Tab:Selected",
|
||||
"Tab:Closed",
|
||||
"Tab:Move",
|
||||
]);
|
||||
|
||||
GlobalEventDispatcher.registerListener(this, [
|
||||
"Browser:LoadManifest",
|
||||
"Browser:Quit",
|
||||
"Fonts:Reload",
|
||||
@ -1855,10 +1851,6 @@ var BrowserApp = {
|
||||
break;
|
||||
}
|
||||
|
||||
case "Session:Restore":
|
||||
GlobalEventDispatcher.dispatch("Session:Restore", data);
|
||||
break;
|
||||
|
||||
case "Session:Stop":
|
||||
browser.stop();
|
||||
break;
|
||||
|
@ -7,7 +7,7 @@
|
||||
|
||||
<window id="main-window"
|
||||
onload="startup();"
|
||||
windowtype="navigator:geckoview"
|
||||
windowtype="navigator:browser"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
|
||||
<browser id="content" type="content" primary="true" src="about:blank" flex="1"/>
|
||||
|
Loading…
Reference in New Issue
Block a user