[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]
[tor-commits] [tor-browser/tor-browser-60.6.1esr-8.5-1] fixup! Bug 28329 - Part 4. Add new Tor Bootstrapping and configuration screens
commit 7b5f5ee887cd6fd865e86784ad536b4c0136ce83
Author: Matthew Finkel <Matthew.Finkel@xxxxxxxxx>
Date: Tue Apr 9 17:52:28 2019 +0000
fixup! Bug 28329 - Part 4. Add new Tor Bootstrapping and configuration screens
---
.../app/src/main/res/layout/tor_bootstrap.xml | 9 +-
.../base/java/org/mozilla/gecko/BrowserApp.java | 2 +-
.../gecko/torbootstrap/TorBootstrapPanel.java | 203 +++++++++++++++++----
.../mozilla/gecko/torbootstrap/TorPreferences.java | 13 +-
4 files changed, 176 insertions(+), 51 deletions(-)
diff --git a/mobile/android/app/src/main/res/layout/tor_bootstrap.xml b/mobile/android/app/src/main/res/layout/tor_bootstrap.xml
index ce2b1c910a44..af9c7d11d3f2 100644
--- a/mobile/android/app/src/main/res/layout/tor_bootstrap.xml
+++ b/mobile/android/app/src/main/res/layout/tor_bootstrap.xml
@@ -74,13 +74,10 @@
android:tint="#ffffffff"
android:layout_height="wrap_content"
android:layout_width="match_parent"
- android:layout_marginTop="130dp"
android:layout_marginBottom="37dp"
- android:layout_marginRight="95dp"
- android:layout_marginLeft="95dp"
+ android:layout_marginRight="10dp"
+ android:layout_marginLeft="10dp"
android:layout_centerHorizontal="true"
android:layout_below="@id/tor_bootstrap_settings_gear"
- android:layout_above="@id/tor_bootstrap_last_status_message"
- android:paddingLeft="20dp"
- android:paddingRight="20dp"/>
+ android:layout_above="@id/tor_bootstrap_last_status_message" />
</RelativeLayout>
diff --git a/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java b/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java
index dce3dc1548c2..006d5c11f210 100644
--- a/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java
+++ b/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java
@@ -3134,7 +3134,7 @@ public class BrowserApp extends GeckoApp
// When the content loaded in the background (such as about:tor),
// it was loaded while mBrowserChrome was GONE. We should refresh the
// height now so the page is rendered correctly.
- Tabs.getInstance().getSelectedTab().doReload(false);
+ Tabs.getInstance().getSelectedTab().doReload(true);
// If we finished, then Tor bootstrapped 100%
mTorNeedsStart = false;
diff --git a/mobile/android/base/java/org/mozilla/gecko/torbootstrap/TorBootstrapPanel.java b/mobile/android/base/java/org/mozilla/gecko/torbootstrap/TorBootstrapPanel.java
index 8d42b13a2a8e..2ee4c2528691 100644
--- a/mobile/android/base/java/org/mozilla/gecko/torbootstrap/TorBootstrapPanel.java
+++ b/mobile/android/base/java/org/mozilla/gecko/torbootstrap/TorBootstrapPanel.java
@@ -7,7 +7,6 @@ package org.mozilla.gecko.torbootstrap;
import android.app.Activity;
import android.content.Intent;
-import android.graphics.drawable.Animatable2;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Bundle;
@@ -16,6 +15,7 @@ import android.support.v4.content.LocalBroadcastManager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
@@ -44,6 +44,8 @@ public class TorBootstrapPanel extends FirstrunPanel implements TorBootstrapLogg
protected Activity mActContext;
protected TorBootstrapPager.TorBootstrapController mBootstrapController;
+ private ViewTreeLayoutListener mViewTreeLayoutListener;
+
// These are used by the background AlphaChanging thread for dynamically changing
// the alpha value of the Onion during bootstrap.
private int mOnionCurrentAlpha = 255;
@@ -85,6 +87,155 @@ public class TorBootstrapPanel extends FirstrunPanel implements TorBootstrapLogg
}
}
+ // Android tries scaling the image as a square. Create a modified ViewPort via padding
+ // top, left, right, and bottom such that the image aspect ratio is correct.
+ private void setOnionImgLayout() {
+ if (mRoot == null) {
+ Log.i(LOGTAG, "setOnionImgLayout: mRoot is null");
+ return;
+ }
+
+ ImageView onionImg = (ImageView) mRoot.findViewById(R.id.tor_bootstrap_onion);
+ if (onionImg == null) {
+ Log.i(LOGTAG, "setOnionImgLayout: onionImg is null");
+ return;
+ }
+
+ // Dimensions of the SVG. If the image is ever changed, update these values. The
+ // SVG viewport is 2dp wider due to clipping.
+ final double imgHeight = 289.;
+ final double imgWidth = 247.;
+
+ // Dimensions of the current ImageView
+ final int currentHeight = onionImg.getHeight();
+ final int currentWidth = onionImg.getWidth();
+
+ // If we only consider one dimension of the image, calculate the expected value
+ // of the other dimension (width vs. height).
+ final int expectedHeight = (int) (currentWidth*imgHeight/imgWidth);
+ final int expectedWidth = (int) (currentHeight*imgWidth/imgHeight);
+
+ // Set current values as default.
+ int newWidth = currentWidth;
+ int newHeight = currentHeight;
+
+ Log.d(LOGTAG, "Current Top=" + onionImg.getTop());
+ Log.d(LOGTAG, "Current Height=" + currentHeight);
+ Log.d(LOGTAG, "Current Width=" + currentWidth);
+ Log.d(LOGTAG, "Expected height=" + expectedHeight);
+ Log.d(LOGTAG, "Expected width=" + expectedWidth);
+
+ // Configure the width or height based on its expected value. This is based on
+ // the intuition that:
+ // - If the device is in portrait mode, then the device's height is (likely)
+ // greater than its width. When this is the case, then:
+ // - The image's View object is likely using all available vertical area
+ // (but the image is bounded by the width of the device due to
+ // maintaining the scaling factor).
+ // - However, the height and width of the graphic are equal (because
+ // Android enforces this).
+ // - The width should be less than the height (this is a property of
+ // the image itself).
+ // - The width should be proportional to the imgHeight and imgWidth
+ // defined above.
+ // Adjust the height when the current width is less than the expected width.
+ // The width is the limiting-factor, therefore choose the height proportional
+ // to the current width.
+ //
+ // - The opposite is likely true when the device is in landscape mode with
+ // respect to the height and width. Adjust the width when the height is less
+ // than the expected height. The height is the limiting-factor, therefore
+ // choose the width proportional to the current height.
+ //
+ // Subtract 1 from the expected value as a way of accounting for rounding
+ // error.
+ if (currentWidth < (expectedWidth - 1)) {
+ newHeight = expectedHeight;
+ } else if (currentHeight < (expectedHeight - 1)) {
+ newWidth = expectedWidth;
+ }
+
+ Log.d(LOGTAG, "New height=" + newHeight);
+ Log.d(LOGTAG, "New width=" + newWidth);
+
+ // Define the padding as the available space between the current height (as it
+ // is displayed to the user) and the new height (as it was calculated above).
+ int verticalPadding = currentHeight - newHeight;
+ int sidePadding = currentWidth - newWidth;
+ int leftPadding = 0;
+ int topPadding = 0;
+ int bottomPadding = 0;
+ int rightPadding = 0;
+
+ // If the width of the image is greater than 600dp, then cap it at 702x600 (HxW).
+ // Furthermore, if the width is "near" 600dp (within 100dp), then decrease the
+ // dimensions to 468x400 dp. This should "look" better on lower-resolution
+ // devices.
+ final int MAXIMUM_WIDTH = 600;
+ final int distanceFromMaxWidth = newWidth - MAXIMUM_WIDTH;
+ final boolean isNearMaxWidth = Math.abs(distanceFromMaxWidth) < 100;
+ if ((newWidth > MAXIMUM_WIDTH) || isNearMaxWidth) {
+ if (isNearMaxWidth) {
+ // If newWidth is near MAX_WIDTH, then add additional padding (therefore
+ // decreasing the width by an additional 200dp).
+ sidePadding += 200;
+ }
+
+ final int paddingSpaceAvailable = (distanceFromMaxWidth > 0) ? distanceFromMaxWidth : 0;
+ sidePadding += paddingSpaceAvailable;
+
+ final int newWidthWithoutPadding = currentWidth - sidePadding;
+
+ final int newHeightWithoutPadding = (int) (newWidthWithoutPadding*imgHeight/imgWidth);
+
+ Log.d(LOGTAG, "New width without padding=" + newWidthWithoutPadding);
+ Log.d(LOGTAG, "New height without padding=" + newHeightWithoutPadding);
+
+ verticalPadding = currentHeight - newHeightWithoutPadding;
+ }
+
+ Log.d(LOGTAG, "New top padding=" + verticalPadding);
+ Log.d(LOGTAG, "New side padding=" + sidePadding);
+
+ if (verticalPadding < 0) {
+ Log.i(LOGTAG, "vertical padding is " + verticalPadding);
+ verticalPadding = 0;
+ } else {
+ // Place 4/5 of padding at top, and 1/5 of padding at bottom.
+ topPadding = (int) (verticalPadding*4)/5;
+ bottomPadding = (int) verticalPadding/5;
+ }
+
+ if (sidePadding < 0) {
+ Log.i(LOGTAG, "side padding is " + sidePadding);
+ leftPadding = 0;
+ rightPadding = 0;
+ } else {
+ // Divide the padding equally on the left and right side.
+ leftPadding = (int) sidePadding/2;
+ rightPadding = leftPadding;
+ }
+
+ // Create a padding-box around the image and let Android fill the box with
+ // the image. Android will scale the width and height independently, so the
+ // end result should be a correctly-sized graphic.
+ onionImg.setPadding(leftPadding, topPadding, rightPadding, bottomPadding);
+
+ // Separately scale x- and y-dimension.
+ onionImg.setScaleType(ImageView.ScaleType.FIT_XY);
+
+ // Invalidate the view because the image disappears (is not redrawn) sometimes when
+ // the screen is rotated.
+ onionImg.invalidate();
+ }
+
+ private class ViewTreeLayoutListener implements ViewTreeObserver.OnGlobalLayoutListener {
+ @Override
+ public void onGlobalLayout() {
+ TorBootstrapPanel.this.setOnionImgLayout();
+ }
+ }
+
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstance) {
mRoot = (ViewGroup) inflater.inflate(R.layout.tor_bootstrap, container, false);
@@ -121,6 +272,12 @@ public class TorBootstrapPanel extends FirstrunPanel implements TorBootstrapLogg
TorLogEventListener.addLogger(this);
+ // Add a callback for notification when the layout is complete and all components
+ // are measured. Waiting until the layout is complete is necessary before we correctly
+ // set the size of the onion. Cache the listener so we may remove it later.
+ mViewTreeLayoutListener = new ViewTreeLayoutListener();
+ mRoot.getViewTreeObserver().addOnGlobalLayoutListener(mViewTreeLayoutListener);
+
return mRoot;
}
@@ -193,6 +350,9 @@ public class TorBootstrapPanel extends FirstrunPanel implements TorBootstrapLogg
mOnionAlphaChangerRunning = false;
}
close();
+
+ // Remove the listener when we're done
+ mRoot.getViewTreeObserver().removeOnGlobalLayoutListener(mViewTreeLayoutListener);
}
}
@@ -281,9 +441,9 @@ public class TorBootstrapPanel extends FirstrunPanel implements TorBootstrapLogg
Log.i(LOGTAG, "mChangeOnionAlphaThread.getState(): is terminated");
mChangeOnionAlphaThread = null;
} else {
- // Don't null the reference in this case because then we'll start another
- // background thread. We are currently in an unknown state, simply set
- // the Running flag as false.
+ // The reference is not nulled in this case because another
+ // background thread would start otherwise. The thread is currently in
+ // an unknown state, simply set the Running flag as false.
Log.w(LOGTAG, "We're in an unexpected state. mChangeOnionAlphaThread.getState(): " + mChangeOnionAlphaThread.getState());
synchronized(mOnionAlphaChangerLock) {
@@ -302,7 +462,7 @@ public class TorBootstrapPanel extends FirstrunPanel implements TorBootstrapLogg
// Synchronization across threads should not be necessary because there
// shouldn't be any other threads relying on mOnionAlphaChangerRunning.
- // We do this purely for safety.
+ // Do this purely for safety.
synchronized(mOnionAlphaChangerLock) {
mOnionAlphaChangerRunning = true;
}
@@ -317,7 +477,7 @@ public class TorBootstrapPanel extends FirstrunPanel implements TorBootstrapLogg
Log.w(LOGTAG, "startBootstrapping: mRoot is null?");
return;
}
- // We're starting bootstrap, transition into the bootstrapping-tor-panel
+ // Start bootstrap process and transition into the bootstrapping-tor-panel
Button connectButton = mRoot.findViewById(R.id.tor_bootstrap_connect);
if (connectButton == null) {
Log.w(LOGTAG, "startBootstrapping: connectButton is null?");
@@ -326,17 +486,7 @@ public class TorBootstrapPanel extends FirstrunPanel implements TorBootstrapLogg
ImageView onionImg = (ImageView) mRoot.findViewById(R.id.tor_bootstrap_onion);
- // Replace the current non-animated image with the animation
- onionImg.setImageResource(R.drawable.tor_spinning_onion);
-
Drawable drawableOnion = onionImg.getDrawable();
- if (Build.VERSION.SDK_INT >= 23 && drawableOnion instanceof Animatable2) {
- Animatable2 spinningOnion = (Animatable2) drawableOnion;
- // Begin spinning
- spinningOnion.start();
- } else {
- Log.i(LOGTAG, "Animatable2 is not supported (or bad inheritance), version: " + Build.VERSION.SDK_INT);
- }
mOnionCurrentAlpha = 255;
// The onion should have 100% alpha, begin decreasing it.
@@ -388,27 +538,6 @@ public class TorBootstrapPanel extends FirstrunPanel implements TorBootstrapLogg
Drawable drawableOnion = onionImg.getDrawable();
- // If the connect button wasn't pressed previously, then this object is
- // not an animation (it is most likely a BitmapDrawable). Only manipulate
- // it when it is an Animatable2.
- if (Build.VERSION.SDK_INT >= 23 && drawableOnion instanceof Animatable2) {
- Animatable2 spinningOnion = (Animatable2) drawableOnion;
- // spinningOnion is null if we didn't previously call startBootstrapping.
- // If we reach here and spinningOnion is null, then there is likely a bug
- // because stopBootstrapping() is called only when the user selects the
- // gear button and we should only reach this block if the user pressed the
- // connect button (thus creating and enabling the animation) and then
- // pressing the gear button. Therefore, if the drawableOnion is an
- // Animatable2, then spinningOnion should be non-null.
- if (spinningOnion != null) {
- spinningOnion.stop();
-
- onionImg.setImageResource(R.drawable.tor_spinning_onion);
- }
- } else {
- Log.i(LOGTAG, "Animatable2 is not supported (or bad inheritance), version: " + Build.VERSION.SDK_INT);
- }
-
// Reset the onion's alpha value.
onionImg.setImageAlpha(255);
diff --git a/mobile/android/base/java/org/mozilla/gecko/torbootstrap/TorPreferences.java b/mobile/android/base/java/org/mozilla/gecko/torbootstrap/TorPreferences.java
index 9a8468292e7d..87ce1ec4bec6 100644
--- a/mobile/android/base/java/org/mozilla/gecko/torbootstrap/TorPreferences.java
+++ b/mobile/android/base/java/org/mozilla/gecko/torbootstrap/TorPreferences.java
@@ -342,7 +342,7 @@ public class TorPreferences extends AppCompatPreferenceActivity {
Log.i(LOGTAG, "disableBridges: bridgesProvide is not null");
pref = bridgesProvide;
} else {
- Log.w(LOGTAG, "disableBridges: all the expected preferences are is null?");
+ Log.w(LOGTAG, "disableBridges: all of the expected preferences are null?");
return;
}
@@ -396,7 +396,7 @@ public class TorPreferences extends AppCompatPreferenceActivity {
// such that it is synchronized with the widget.
final SwitchPreference bridgesEnabled = (SwitchPreference) TorNetworkBridgesEnabledPreference.this.findPreference(PREFS_BRIDGES_ENABLED);
if (bridgesEnabled == null) {
- Log.w(LOGTAG, "onCreate: bridgesEnabled is null?");
+ Log.w(LOGTAG, "onClick: bridgesEnabled is null?");
return;
}
@@ -422,11 +422,10 @@ public class TorPreferences extends AppCompatPreferenceActivity {
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
- setTitle(R.string.pref_tor_network_title);
final SwitchPreference bridgesEnabled = (SwitchPreference) findPreference(PREFS_BRIDGES_ENABLED);
if (bridgesEnabled == null) {
- Log.w(LOGTAG, "onCreate: bridgesEnabled is null?");
+ Log.w(LOGTAG, "onViewCreated: bridgesEnabled is null?");
return;
}
@@ -927,9 +926,9 @@ public class TorPreferences extends AppCompatPreferenceActivity {
}
if (bridgesLine2 != null) {
- // If bridgesLine1 was not null, then append a newline.
Log.i(LOGTAG, "bridgesLine2 is not null.");
if (bridgesLines != null) {
+ // If bridgesLine1 was not null, then append a newline.
bridgesLines += "\n" + bridgesLine2;
} else {
bridgesLines = bridgesLine2;
@@ -937,9 +936,9 @@ public class TorPreferences extends AppCompatPreferenceActivity {
}
if (bridgesLine3 != null) {
- // If bridgesLine1 was not null, then append a newline.
Log.i(LOGTAG, "bridgesLine3 is not null.");
if (bridgesLines != null) {
+ // If bridgesLine1 or bridgesLine2 were not null, then append a newline.
bridgesLines += "\n" + bridgesLine3;
} else {
bridgesLines = bridgesLine3;
@@ -954,11 +953,11 @@ public class TorPreferences extends AppCompatPreferenceActivity {
}
if (bridgesLines == null) {
- Log.i(LOGTAG, "provideBridge is empty. Disabling.");
// If provided bridges are null/empty, then only disable all bridges if
// the user did not select a built-in bridge
String configuredBuiltinBridges = getBridges(bridgesProvide.getSharedPreferences(), PREFS_BRIDGES_TYPE);
if (configuredBuiltinBridges == null) {
+ Log.i(LOGTAG, "Custom bridges are empty. Disabling.");
disableBridges(this);
}
return;
_______________________________________________
tor-commits mailing list
tor-commits@xxxxxxxxxxxxxxxxxxxx
https://lists.torproject.org/cgi-bin/mailman/listinfo/tor-commits