Bug 1029646 - Update layout direction of configuration and DecorView, r=sebastian draft
authormaliu <max@mxli.us>
Tue, 03 Jan 2017 15:14:59 +0800
changeset 455313 642098f5d23976dbee1c238e599f1c79b2c07a50
parent 455176 c91249f41e3766274131a84f9157a4d9d9949520
child 540944 46a8f05676f6967a5f8b7160ebdba9fd65e705c7
push id40189
push userbmo:max@mxli.us
push dateTue, 03 Jan 2017 13:40:40 +0000
reviewerssebastian
bugs1029646
milestone53.0a1
Bug 1029646 - Update layout direction of configuration and DecorView, r=sebastian MozReview-Commit-ID: FiDwoX45yV9
mobile/android/base/java/org/mozilla/gecko/BrowserLocaleManager.java
mobile/android/base/java/org/mozilla/gecko/GeckoApp.java
mobile/android/base/java/org/mozilla/gecko/preferences/GeckoPreferences.java
mobile/android/base/java/org/mozilla/gecko/toolbar/BrowserToolbar.java
mobile/android/base/java/org/mozilla/gecko/toolbar/BrowserToolbarTabletBase.java
mobile/android/base/java/org/mozilla/gecko/util/ViewUtil.java
--- a/mobile/android/base/java/org/mozilla/gecko/BrowserLocaleManager.java
+++ b/mobile/android/base/java/org/mozilla/gecko/BrowserLocaleManager.java
@@ -21,16 +21,17 @@ import org.mozilla.gecko.util.GeckoJarRe
 
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.SharedPreferences;
 import android.content.res.Configuration;
 import android.content.res.Resources;
+import android.os.Build;
 import android.util.Log;
 
 /**
  * This class manages persistence, application, and otherwise handling of
  * user-specified locales.
  *
  * Of note:
  *
@@ -290,16 +291,21 @@ public class BrowserLocaleManager implem
     @Override
     public void updateConfiguration(Context context, Locale locale) {
         Resources res = context.getResources();
         Configuration config = res.getConfiguration();
 
         // We should use setLocale, but it's unexpectedly missing
         // on real devices.
         config.locale = locale;
+        //  LayoutDirection is also updated in setLocale, do this manually.
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+            config.setLayoutDirection(locale);
+        }
+
         res.updateConfiguration(config, null);
     }
 
     private SharedPreferences getSharedPreferences(Context context) {
         return GeckoSharedPrefs.forApp(context);
     }
 
     /**
--- a/mobile/android/base/java/org/mozilla/gecko/GeckoApp.java
+++ b/mobile/android/base/java/org/mozilla/gecko/GeckoApp.java
@@ -105,16 +105,17 @@ import android.widget.ListView;
 import android.widget.RelativeLayout;
 import android.widget.SimpleAdapter;
 import android.widget.TextView;
 import android.widget.Toast;
 
 import org.json.JSONArray;
 import org.json.JSONException;
 import org.json.JSONObject;
+import org.mozilla.gecko.util.ViewUtil;
 
 import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
 import java.lang.ref.WeakReference;
 import java.net.URL;
 import java.util.ArrayList;
@@ -1444,16 +1445,19 @@ public abstract class GeckoApp
         if (!ThreadUtils.isOnUiThread()) {
             throw new RuntimeException("onLocaleReady must always be called from the UI thread.");
         }
 
         final Locale loc = Locales.parseLocaleCode(locale);
         if (loc.equals(mLastLocale)) {
             Log.d(LOGTAG, "New locale same as old; onLocaleReady has nothing to do.");
         }
+        BrowserLocaleManager.getInstance().updateConfiguration(GeckoApp.this, loc);
+        ViewUtil.setLayoutDirection(getWindow().getDecorView(), loc);
+        refreshChrome();
 
         // The URL bar hint needs to be populated.
         TextView urlBar = (TextView) findViewById(R.id.url_bar_title);
         if (urlBar != null) {
             final String hint = getResources().getString(R.string.url_bar_default_text);
             urlBar.setHint(hint);
         } else {
             Log.d(LOGTAG, "No URL bar in GeckoApp. Not loading localized hint string.");
--- a/mobile/android/base/java/org/mozilla/gecko/preferences/GeckoPreferences.java
+++ b/mobile/android/base/java/org/mozilla/gecko/preferences/GeckoPreferences.java
@@ -45,16 +45,17 @@ import org.mozilla.gecko.updater.UpdateS
 import org.mozilla.gecko.util.BundleEventListener;
 import org.mozilla.gecko.util.ContextUtils;
 import org.mozilla.gecko.util.EventCallback;
 import org.mozilla.gecko.util.GeckoBundle;
 import org.mozilla.gecko.util.HardwareUtils;
 import org.mozilla.gecko.util.InputOptionsUtils;
 import org.mozilla.gecko.util.NativeJSObject;
 import org.mozilla.gecko.util.ThreadUtils;
+import org.mozilla.gecko.util.ViewUtil;
 
 import android.annotation.TargetApi;
 import android.app.AlertDialog;
 import android.app.Dialog;
 import android.app.Fragment;
 import android.app.FragmentManager;
 import android.app.NotificationManager;
 import android.content.ContentResolver;
@@ -75,22 +76,26 @@ import android.preference.Preference.OnP
 import android.preference.Preference.OnPreferenceClickListener;
 import android.preference.PreferenceActivity;
 import android.preference.PreferenceGroup;
 import android.preference.SwitchPreference;
 import android.preference.TwoStatePreference;
 import android.support.design.widget.Snackbar;
 import android.support.design.widget.TextInputLayout;
 import android.support.v4.content.LocalBroadcastManager;
+import android.support.v4.content.res.ResourcesCompat;
+import android.support.v4.text.TextUtilsCompat;
+import android.support.v4.view.ViewCompat;
 import android.support.v7.app.ActionBar;
 import android.text.Editable;
 import android.text.InputType;
 import android.text.TextUtils;
 import android.text.TextWatcher;
 import android.util.Log;
+import android.view.Menu;
 import android.view.MenuItem;
 import android.view.View;
 import android.widget.AdapterView;
 import android.widget.EditText;
 import android.widget.LinearLayout;
 import android.widget.ListAdapter;
 import android.widget.ListView;
 
@@ -257,16 +262,24 @@ public class GeckoPreferences
             setTitle(title);
         }
     }
 
     private void onLocaleChanged(Locale newLocale) {
         Log.d(LOGTAG, "onLocaleChanged: " + newLocale);
 
         BrowserLocaleManager.getInstance().updateConfiguration(getApplicationContext(), newLocale);
+        //  If activity is not recreated, also update locale to current activity configuration
+        BrowserLocaleManager.getInstance().updateConfiguration(GeckoPreferences.this, newLocale);
+        ViewUtil.setLayoutDirection(getWindow().getDecorView(), newLocale);
+
+        //  Force update navigate up icon by current layout direction
+        final ActionBar actionBar = getSupportActionBar();
+        actionBar.setHomeAsUpIndicator(android.support.v7.appcompat.R.drawable.abc_ic_ab_back_mtrl_am_alpha);
+
         this.lastLocale = newLocale;
 
         if (isMultiPane()) {
             // This takes care of the left pane.
             invalidateHeaders();
 
             // Detach and reattach the current prefs pane so that it
             // reflects the new locale.
--- a/mobile/android/base/java/org/mozilla/gecko/toolbar/BrowserToolbar.java
+++ b/mobile/android/base/java/org/mozilla/gecko/toolbar/BrowserToolbar.java
@@ -354,16 +354,17 @@ public abstract class BrowserToolbar ext
         this.progressBar = progressBar;
     }
 
     public void setTabHistoryController(TabHistoryController tabHistoryController) {
         this.tabHistoryController = tabHistoryController;
     }
 
     public void refresh() {
+        progressBar.setImageDrawable(getResources().getDrawable(R.drawable.progress));
         urlDisplayLayout.dismissSiteIdentityPopup();
     }
 
     public boolean onBackPressed() {
         // If we exit editing mode during the animation,
         // we're put into an inconsistent state (bug 1017276).
         if (isEditing() && !isAnimating()) {
             Telemetry.sendUIEvent(TelemetryContract.Event.CANCEL,
--- a/mobile/android/base/java/org/mozilla/gecko/toolbar/BrowserToolbarTabletBase.java
+++ b/mobile/android/base/java/org/mozilla/gecko/toolbar/BrowserToolbarTabletBase.java
@@ -123,16 +123,23 @@ abstract class BrowserToolbarTabletBase 
     @Override
     protected void updateNavigationButtons(final Tab tab) {
         backButton.setEnabled(canDoBack(tab));
         animateForwardButton(
                 canDoForward(tab) ? ForwardButtonAnimation.SHOW : ForwardButtonAnimation.HIDE);
     }
 
     @Override
+    public void refresh() {
+        super.refresh();
+        forwardButton.setImageDrawable(getResources().getDrawable(R.drawable.ic_menu_forward));
+        backButton.setImageDrawable(getResources().getDrawable(R.drawable.ic_menu_back));
+    }
+
+    @Override
     public void setNextFocusDownId(int nextId) {
         super.setNextFocusDownId(nextId);
         backButton.setNextFocusDownId(nextId);
         forwardButton.setNextFocusDownId(nextId);
     }
 
     @Override
     public void setPrivateMode(final boolean isPrivate) {
--- a/mobile/android/base/java/org/mozilla/gecko/util/ViewUtil.java
+++ b/mobile/android/base/java/org/mozilla/gecko/util/ViewUtil.java
@@ -1,23 +1,27 @@
 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; 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.util;
 
 import android.content.res.TypedArray;
 import android.os.Build;
+import android.support.v4.text.TextUtilsCompat;
 import android.support.v4.view.MarginLayoutParamsCompat;
+import android.support.v4.view.ViewCompat;
 import android.view.View;
 import android.view.ViewGroup;
 
 import org.mozilla.gecko.AppConstants;
 import org.mozilla.gecko.R;
 
+import java.util.Locale;
+
 public class ViewUtil {
 
     /**
      * Enable a circular touch ripple for a given view. This is intended for borderless views,
      * such as (3-dot) menu buttons.
      *
      * Because of platform limitations a square ripple is used on Android 4.
      */
@@ -46,9 +50,26 @@ public class ViewUtil {
                 layoutParams.rightMargin = marginStart;
             } else {
                 layoutParams.leftMargin = marginStart;
             }
         } else {
             MarginLayoutParamsCompat.setMarginStart(layoutParams, marginStart);
         }
     }
+
+    /**
+     * Force set layout direction to RTL or LTR by Locale.
+     * @param view
+     * @param locale
+     */
+    public static void setLayoutDirection(View view, Locale locale) {
+        switch (TextUtilsCompat.getLayoutDirectionFromLocale(locale)) {
+            case ViewCompat.LAYOUT_DIRECTION_RTL:
+                ViewCompat.setLayoutDirection(view, ViewCompat.LAYOUT_DIRECTION_RTL);
+                break;
+            case ViewCompat.LAYOUT_DIRECTION_LTR:
+            default:
+                ViewCompat.setLayoutDirection(view, ViewCompat.LAYOUT_DIRECTION_LTR);
+                break;
+        }
+    }
 }