зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1421174 - Remove old AddToHomeScreenPromotion; r=jchen
Deprecated by offering full support for Progressive Web Applications. Differential Revision: https://phabricator.services.mozilla.com/D7696 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
4c95ba0b3d
Коммит
53dceac9f9
|
@ -53,24 +53,6 @@
|
|||
"max": "100"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "promote-add-to-homescreen",
|
||||
"buckets": {
|
||||
"max": "100",
|
||||
"min": "50"
|
||||
},
|
||||
"last_modified": 1467705654772,
|
||||
"values": {
|
||||
"lastVisitMaximumAgeMs": 600000,
|
||||
"minimumTotalVisits": 5,
|
||||
"lastVisitMinimumAgeMs": 30000
|
||||
},
|
||||
"id": "20d278d7-0d35-4811-8f01-bf24e31ba51b",
|
||||
"match": {
|
||||
"appId": "^org.mozilla.fennec|^org.mozilla.firefox_beta$"
|
||||
},
|
||||
"schema": 1467705310595
|
||||
},
|
||||
{
|
||||
"name": "offline-cache",
|
||||
"buckets": {
|
||||
|
|
|
@ -211,10 +211,6 @@
|
|||
android:launchMode="singleTop"
|
||||
android:theme="@style/OverlayActivity" />
|
||||
|
||||
<activity android:name="org.mozilla.gecko.promotion.HomeScreenPrompt"
|
||||
android:launchMode="singleTop"
|
||||
android:theme="@style/OverlayActivity" />
|
||||
|
||||
<!-- The main reason for the Tab Queue build flag is to not mess with the VIEW intent filter
|
||||
before the rest of the plumbing is in place -->
|
||||
|
||||
|
|
|
@ -118,7 +118,6 @@ import org.mozilla.gecko.overlays.ui.ShareDialog;
|
|||
import org.mozilla.gecko.permissions.Permissions;
|
||||
import org.mozilla.gecko.preferences.ClearOnShutdownPref;
|
||||
import org.mozilla.gecko.preferences.GeckoPreferences;
|
||||
import org.mozilla.gecko.promotion.AddToHomeScreenPromotion;
|
||||
import org.mozilla.gecko.promotion.ReaderViewBookmarkPromotion;
|
||||
import org.mozilla.gecko.prompts.Prompt;
|
||||
import org.mozilla.gecko.reader.ReaderModeUtils;
|
||||
|
@ -318,7 +317,6 @@ public class BrowserApp extends GeckoApp
|
|||
private final TelemetryCorePingDelegate mTelemetryCorePingDelegate = new TelemetryCorePingDelegate();
|
||||
|
||||
private final List<BrowserAppDelegate> delegates = Collections.unmodifiableList(Arrays.asList(
|
||||
new AddToHomeScreenPromotion(),
|
||||
new ScreenshotDelegate(),
|
||||
new BookmarkStateChangeDelegate(),
|
||||
new ReaderViewBookmarkPromotion(),
|
||||
|
|
|
@ -28,9 +28,6 @@ public class Experiments {
|
|||
// Synchronizing the catalog of downloadable content from Kinto
|
||||
public static final String DOWNLOAD_CONTENT_CATALOG_SYNC = "download-content-catalog-sync";
|
||||
|
||||
// Promotion for "Add to homescreen"
|
||||
public static final String PROMOTE_ADD_TO_HOMESCREEN = "promote-add-to-homescreen";
|
||||
|
||||
// Promotion to bookmark reader-view items after entering reader view three times (Bug 1247689)
|
||||
public static final String TRIPLE_READERVIEW_BOOKMARK_PROMPT = "triple-readerview-bookmark-prompt";
|
||||
|
||||
|
|
|
@ -1,243 +0,0 @@
|
|||
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
package org.mozilla.gecko.promotion;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.CallSuper;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.util.Log;
|
||||
|
||||
import org.mozilla.gecko.switchboard.SwitchBoard;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import org.mozilla.gecko.AboutPages;
|
||||
import org.mozilla.gecko.BrowserApp;
|
||||
import org.mozilla.gecko.GeckoProfile;
|
||||
import org.mozilla.gecko.Tab;
|
||||
import org.mozilla.gecko.Tabs;
|
||||
import org.mozilla.gecko.db.BrowserContract;
|
||||
import org.mozilla.gecko.db.BrowserDB;
|
||||
import org.mozilla.gecko.db.UrlAnnotations;
|
||||
import org.mozilla.gecko.delegates.TabsTrayVisibilityAwareDelegate;
|
||||
import org.mozilla.gecko.Experiments;
|
||||
import org.mozilla.gecko.util.ThreadUtils;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
import ch.boye.httpclientandroidlib.util.TextUtils;
|
||||
|
||||
/**
|
||||
* Promote "Add to home screen" if user visits website often.
|
||||
*/
|
||||
public class AddToHomeScreenPromotion extends TabsTrayVisibilityAwareDelegate implements Tabs.OnTabsChangedListener {
|
||||
public static class URLHistory {
|
||||
public final long visits;
|
||||
public final long lastVisit;
|
||||
|
||||
private URLHistory(long visits, long lastVisit) {
|
||||
this.visits = visits;
|
||||
this.lastVisit = lastVisit;
|
||||
}
|
||||
}
|
||||
|
||||
private static final String LOGTAG = "GeckoPromoteShortcut";
|
||||
|
||||
private static final String EXPERIMENT_MINIMUM_TOTAL_VISITS = "minimumTotalVisits";
|
||||
private static final String EXPERIMENT_LAST_VISIT_MINIMUM_AGE = "lastVisitMinimumAgeMs";
|
||||
private static final String EXPERIMENT_LAST_VISIT_MAXIMUM_AGE = "lastVisitMaximumAgeMs";
|
||||
|
||||
private WeakReference<Activity> activityReference;
|
||||
private boolean isEnabled;
|
||||
private int minimumVisits;
|
||||
private int lastVisitMinimumAgeMs;
|
||||
private int lastVisitMaximumAgeMs;
|
||||
|
||||
@CallSuper
|
||||
@Override
|
||||
public void onCreate(BrowserApp browserApp, Bundle savedInstanceState) {
|
||||
super.onCreate(browserApp, savedInstanceState);
|
||||
activityReference = new WeakReference<Activity>(browserApp);
|
||||
|
||||
initializeExperiment(browserApp);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume(BrowserApp browserApp) {
|
||||
Tabs.registerOnTabsChangedListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause(BrowserApp browserApp) {
|
||||
Tabs.unregisterOnTabsChangedListener(this);
|
||||
}
|
||||
|
||||
private void initializeExperiment(Context context) {
|
||||
if (!SwitchBoard.isInExperiment(context, Experiments.PROMOTE_ADD_TO_HOMESCREEN)) {
|
||||
Log.v(LOGTAG, "Experiment not enabled");
|
||||
// Experiment is not enabled. No need to try to read values.
|
||||
return;
|
||||
}
|
||||
|
||||
JSONObject values = SwitchBoard.getExperimentValuesFromJson(context, Experiments.PROMOTE_ADD_TO_HOMESCREEN);
|
||||
if (values == null) {
|
||||
// We didn't get any values for this experiment. Let's disable it instead of picking default
|
||||
// values that might be bad.
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
initializeWithValues(
|
||||
values.getInt(EXPERIMENT_MINIMUM_TOTAL_VISITS),
|
||||
values.getInt(EXPERIMENT_LAST_VISIT_MINIMUM_AGE),
|
||||
values.getInt(EXPERIMENT_LAST_VISIT_MAXIMUM_AGE));
|
||||
} catch (JSONException e) {
|
||||
Log.w(LOGTAG, "Could not read experiment values", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void initializeWithValues(int minimumVisits, int lastVisitMinimumAgeMs, int lastVisitMaximumAgeMs) {
|
||||
this.isEnabled = true;
|
||||
|
||||
this.minimumVisits = minimumVisits;
|
||||
this.lastVisitMinimumAgeMs = lastVisitMinimumAgeMs;
|
||||
this.lastVisitMaximumAgeMs = lastVisitMaximumAgeMs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTabChanged(final Tab tab, Tabs.TabEvents msg, String data) {
|
||||
if (tab == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Tabs.getInstance().isSelectedTab(tab)) {
|
||||
// We only ever want to show this promotion for the current tab.
|
||||
return;
|
||||
}
|
||||
|
||||
if (Tabs.TabEvents.LOADED != msg) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (tab.isPrivate()) {
|
||||
// Never show the prompt for private browsing tabs.
|
||||
return;
|
||||
}
|
||||
|
||||
if (isTabsTrayVisible()) {
|
||||
// We only want to show this prompt if this tab is in the foreground and not on top
|
||||
// of the tabs tray.
|
||||
return;
|
||||
}
|
||||
|
||||
ThreadUtils.postToBackgroundThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
maybeShowPromotionForUrl(tab.getURL(), tab.getTitle());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void maybeShowPromotionForUrl(String url, String title) {
|
||||
if (!isEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
final Context context = activityReference.get();
|
||||
if (context == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!shouldShowPromotion(context, url, title)) {
|
||||
return;
|
||||
}
|
||||
|
||||
HomeScreenPrompt.show(context, url, title);
|
||||
}
|
||||
|
||||
private boolean shouldShowPromotion(Context context, String url, String title) {
|
||||
if (TextUtils.isEmpty(url) || TextUtils.isEmpty(title)) {
|
||||
// We require an URL and a title for the shortcut.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (AboutPages.isAboutPage(url)) {
|
||||
// No promotion for our internal sites.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!url.startsWith("https://")) {
|
||||
// Only promote websites that are served over HTTPS.
|
||||
return false;
|
||||
}
|
||||
|
||||
URLHistory history = getHistoryForURL(context, url);
|
||||
if (history == null) {
|
||||
// There's no history for this URL yet or we can't read it right now. Just ignore.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (history.visits < minimumVisits) {
|
||||
// This URL has not been visited often enough.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (history.lastVisit > System.currentTimeMillis() - lastVisitMinimumAgeMs) {
|
||||
// The last visit is too new. Do not show promotion. This is mostly to avoid that the
|
||||
// promotion shows up for a quick refreshs and in the worst case the last visit could
|
||||
// be the current visit (race).
|
||||
return false;
|
||||
}
|
||||
|
||||
if (history.lastVisit < System.currentTimeMillis() - lastVisitMaximumAgeMs) {
|
||||
// The last visit is to old. Do not show promotion.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (hasAcceptedOrDeclinedHomeScreenShortcut(context, url)) {
|
||||
// The user has already created a shortcut in the past or actively declined to create one.
|
||||
// Let's not ask again for this url - We do not want to be annoying.
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected boolean hasAcceptedOrDeclinedHomeScreenShortcut(Context context, String url) {
|
||||
final UrlAnnotations urlAnnotations = BrowserDB.from(context).getUrlAnnotations();
|
||||
return urlAnnotations.hasAcceptedOrDeclinedHomeScreenShortcut(context.getContentResolver(), url);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static URLHistory getHistoryForURL(Context context, String url) {
|
||||
final GeckoProfile profile = GeckoProfile.get(context);
|
||||
final BrowserDB browserDB = BrowserDB.from(profile);
|
||||
|
||||
Cursor cursor = null;
|
||||
try {
|
||||
cursor = browserDB.getHistoryForURL(context.getContentResolver(), url);
|
||||
|
||||
if (cursor == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (cursor.moveToFirst()) {
|
||||
return new URLHistory(
|
||||
cursor.getInt(cursor.getColumnIndex(BrowserContract.History.VISITS)),
|
||||
cursor.getLong(cursor.getColumnIndex(BrowserContract.History.DATE_LAST_VISITED)));
|
||||
}
|
||||
} finally {
|
||||
if (cursor != null) {
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -1,235 +0,0 @@
|
|||
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
package org.mozilla.gecko.promotion;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.animation.AnimatorSet;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.mozilla.gecko.GeckoApplication;
|
||||
import org.mozilla.gecko.GeckoProfile;
|
||||
import org.mozilla.gecko.Locales;
|
||||
import org.mozilla.gecko.R;
|
||||
import org.mozilla.gecko.Telemetry;
|
||||
import org.mozilla.gecko.TelemetryContract;
|
||||
import org.mozilla.gecko.db.BrowserDB;
|
||||
import org.mozilla.gecko.db.UrlAnnotations;
|
||||
import org.mozilla.gecko.icons.IconCallback;
|
||||
import org.mozilla.gecko.icons.IconResponse;
|
||||
import org.mozilla.gecko.icons.Icons;
|
||||
import org.mozilla.gecko.Experiments;
|
||||
import org.mozilla.gecko.util.ActivityUtils;
|
||||
import org.mozilla.gecko.util.ThreadUtils;
|
||||
|
||||
/**
|
||||
* Prompt to promote adding the current website to the home screen.
|
||||
*/
|
||||
public class HomeScreenPrompt extends Locales.LocaleAwareActivity implements IconCallback {
|
||||
private static final String EXTRA_TITLE = "title";
|
||||
private static final String EXTRA_URL = "url";
|
||||
|
||||
private static final String TELEMETRY_EXTRA = "home_screen_promotion";
|
||||
|
||||
private View containerView;
|
||||
private ImageView iconView;
|
||||
private String title;
|
||||
private String url;
|
||||
private boolean isAnimating;
|
||||
private boolean hasAccepted;
|
||||
private boolean hasDeclined;
|
||||
|
||||
public static void show(Context context, String url, String title) {
|
||||
Intent intent = new Intent(context, HomeScreenPrompt.class);
|
||||
intent.putExtra(EXTRA_TITLE, title);
|
||||
intent.putExtra(EXTRA_URL, url);
|
||||
context.startActivity(intent);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
fetchDataFromIntent();
|
||||
setupViews();
|
||||
loadShortcutIcon();
|
||||
|
||||
slideIn();
|
||||
|
||||
Telemetry.startUISession(TelemetryContract.Session.EXPERIMENT, Experiments.PROMOTE_ADD_TO_HOMESCREEN);
|
||||
|
||||
// Technically this isn't triggered by a "service". But it's also triggered by a background task and without
|
||||
// actual user interaction.
|
||||
Telemetry.sendUIEvent(TelemetryContract.Event.SHOW, TelemetryContract.Method.SERVICE, TELEMETRY_EXTRA);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
|
||||
Telemetry.stopUISession(TelemetryContract.Session.EXPERIMENT, Experiments.PROMOTE_ADD_TO_HOMESCREEN);
|
||||
}
|
||||
|
||||
private void fetchDataFromIntent() {
|
||||
final Bundle extras = getIntent().getExtras();
|
||||
|
||||
title = extras.getString(EXTRA_TITLE);
|
||||
url = extras.getString(EXTRA_URL);
|
||||
}
|
||||
|
||||
private void setupViews() {
|
||||
setContentView(R.layout.homescreen_prompt);
|
||||
|
||||
((TextView) findViewById(R.id.title)).setText(title);
|
||||
|
||||
Uri uri = Uri.parse(url);
|
||||
((TextView) findViewById(R.id.host)).setText(uri.getHost());
|
||||
|
||||
containerView = findViewById(R.id.container);
|
||||
iconView = (ImageView) findViewById(R.id.icon);
|
||||
|
||||
findViewById(R.id.add).setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
hasAccepted = true;
|
||||
|
||||
addToHomeScreen();
|
||||
}
|
||||
});
|
||||
|
||||
findViewById(R.id.close).setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
onDecline();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void addToHomeScreen() {
|
||||
ThreadUtils.postToBackgroundThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
GeckoApplication.createBrowserShortcut(title, url);
|
||||
|
||||
Telemetry.sendUIEvent(TelemetryContract.Event.ACTION, TelemetryContract.Method.BUTTON, TELEMETRY_EXTRA);
|
||||
|
||||
ActivityUtils.goToHomeScreen(HomeScreenPrompt.this);
|
||||
|
||||
finish();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void loadShortcutIcon() {
|
||||
Icons.with(this)
|
||||
.pageUrl(url)
|
||||
.skipNetwork()
|
||||
.skipMemory()
|
||||
.forLauncherIcon()
|
||||
.build()
|
||||
.execute(this);
|
||||
}
|
||||
|
||||
private void slideIn() {
|
||||
containerView.setTranslationY(500);
|
||||
containerView.setAlpha(0);
|
||||
|
||||
final Animator translateAnimator = ObjectAnimator.ofFloat(containerView, "translationY", 0);
|
||||
translateAnimator.setDuration(400);
|
||||
|
||||
final Animator alphaAnimator = ObjectAnimator.ofFloat(containerView, "alpha", 1);
|
||||
alphaAnimator.setStartDelay(200);
|
||||
alphaAnimator.setDuration(600);
|
||||
|
||||
final AnimatorSet set = new AnimatorSet();
|
||||
set.playTogether(alphaAnimator, translateAnimator);
|
||||
set.setStartDelay(400);
|
||||
|
||||
set.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remember that the user rejected creating a home screen shortcut for this URL.
|
||||
*/
|
||||
private void rememberRejection() {
|
||||
ThreadUtils.postToBackgroundThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
final UrlAnnotations urlAnnotations = BrowserDB.from(HomeScreenPrompt.this).getUrlAnnotations();
|
||||
urlAnnotations.insertHomeScreenShortcut(getContentResolver(), url, false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void slideOut() {
|
||||
if (isAnimating) {
|
||||
return;
|
||||
}
|
||||
|
||||
isAnimating = true;
|
||||
|
||||
ObjectAnimator animator = ObjectAnimator.ofFloat(containerView, "translationY", containerView.getHeight());
|
||||
animator.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
finish();
|
||||
}
|
||||
|
||||
});
|
||||
animator.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finish() {
|
||||
super.finish();
|
||||
|
||||
// Don't perform an activity-dismiss animation.
|
||||
overridePendingTransition(0, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
onDecline();
|
||||
}
|
||||
|
||||
private void onDecline() {
|
||||
if (hasDeclined || hasAccepted) {
|
||||
return;
|
||||
}
|
||||
|
||||
rememberRejection();
|
||||
slideOut();
|
||||
|
||||
// Technically not always an action triggered by the "back" button but with the same effect: Finishing this
|
||||
// activity and going back to the previous one.
|
||||
Telemetry.sendUIEvent(TelemetryContract.Event.CANCEL, TelemetryContract.Method.BACK, TELEMETRY_EXTRA);
|
||||
|
||||
hasDeclined = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* User clicked outside of the prompt.
|
||||
*/
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
onDecline();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onIconResponse(IconResponse response) {
|
||||
iconView.setImageBitmap(response.getBitmap());
|
||||
}
|
||||
}
|
|
@ -835,8 +835,6 @@ just addresses the organization to follow, e.g. "This site is run by " -->
|
|||
<!ENTITY whatsnew_notification_title "&brandShortName; is up to date">
|
||||
<!ENTITY whatsnew_notification_summary "Find out what\'s new in this version">
|
||||
|
||||
<!ENTITY promotion_add_page_shortcut "Add page shortcut">
|
||||
|
||||
<!ENTITY helper_first_offline_bookmark_title "Read offline">
|
||||
<!ENTITY helper_first_offline_bookmark_message "Find your Reader View items in Bookmarks, even offline.">
|
||||
<!ENTITY helper_first_offline_bookmark_button "Go to Bookmarks">
|
||||
|
|
|
@ -608,8 +608,6 @@
|
|||
<!-- https://support.mozilla.org/1/mobile/%VERSION%/%OS%/%LOCALE%/new-android -->
|
||||
<string name="whatsnew_notification_url">https://support.mozilla.org/1/mobile/&formatS1;/&formatS2;/&formatS3;/new-android</string>
|
||||
|
||||
<string name="promotion_add_page_shortcut">&promotion_add_page_shortcut;</string>
|
||||
|
||||
<string name="helper_first_offline_bookmark_title">&helper_first_offline_bookmark_title;</string>
|
||||
<string name="helper_first_offline_bookmark_message">&helper_first_offline_bookmark_message;</string>
|
||||
<string name="helper_first_offline_bookmark_button">&helper_first_offline_bookmark_button;</string>
|
||||
|
|
|
@ -1,105 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
|
||||
<merge xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:clipChildren="false"
|
||||
android:clipToPadding="false">
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/container"
|
||||
android:layout_width="@dimen/overlay_prompt_container_width"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom|center"
|
||||
android:background="@android:color/white"
|
||||
android:clickable="true"
|
||||
android:orientation="vertical">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/close"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:layout_marginStart="10dp"
|
||||
android:layout_marginRight="30dp"
|
||||
android:layout_marginEnd="30dp"
|
||||
android:layout_marginTop="30dp"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="2"
|
||||
android:padding="6dp"
|
||||
android:src="@drawable/tab_close_active" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="6dp"
|
||||
android:layout_marginLeft="30dp"
|
||||
android:layout_marginStart="30dp"
|
||||
android:layout_marginTop="30dp"
|
||||
android:layout_toLeftOf="@id/close"
|
||||
android:layout_toStartOf="@id/close"
|
||||
android:fontFamily="sans-serif-light"
|
||||
android:textColor="@color/text_and_tabs_tray_grey"
|
||||
android:textSize="20sp"
|
||||
tools:text="The Pokedex" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/host"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/title"
|
||||
android:layout_marginBottom="20dp"
|
||||
android:layout_marginLeft="30dp"
|
||||
android:layout_marginStart="30dp"
|
||||
android:layout_marginRight="30dp"
|
||||
android:layout_marginEnd="30dp"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:textColor="@color/placeholder_grey"
|
||||
android:textSize="16sp"
|
||||
tools:text="pokedex.org" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/icon"
|
||||
android:layout_width="50dp"
|
||||
android:layout_height="50dp"
|
||||
android:layout_below="@id/host"
|
||||
android:layout_marginBottom="20dp"
|
||||
android:layout_marginLeft="30dp"
|
||||
android:layout_marginStart="30dp"
|
||||
android:src="@drawable/icon" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/add"
|
||||
style="@style/Widget.BaseButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="50dp"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_below="@id/host"
|
||||
android:layout_marginBottom="20dp"
|
||||
android:layout_marginLeft="100dp"
|
||||
android:layout_marginStart="100dp"
|
||||
android:layout_marginRight="30dp"
|
||||
android:layout_marginEnd="30dp"
|
||||
android:background="@drawable/button_background_action_photon_round"
|
||||
android:paddingLeft="16dp"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingRight="16dp"
|
||||
android:paddingEnd="16dp"
|
||||
android:text="@string/promotion_add_page_shortcut"
|
||||
android:maxLines="2"
|
||||
android:ellipsize="end"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="16sp" />
|
||||
|
||||
</RelativeLayout>
|
||||
</merge>
|
Загрузка…
Ссылка в новой задаче