Merge "Import translations. DO NOT MERGE"
diff --git a/res/layout/preference_volume_slider.xml b/res/layout/preference_volume_slider.xml
index 107a8ae..4bed218 100644
--- a/res/layout/preference_volume_slider.xml
+++ b/res/layout/preference_volume_slider.xml
@@ -87,6 +87,7 @@
                 android:id="@+id/suppression_text"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
+                android:paddingStart="16dp"
                 android:layout_gravity="center_vertical|start"
                 android:textAlignment="viewStart"
                 android:singleLine="true"
diff --git a/res/layout/wifi_dialog.xml b/res/layout/wifi_dialog.xml
index 2c4a1ed..f18f21b 100644
--- a/res/layout/wifi_dialog.xml
+++ b/res/layout/wifi_dialog.xml
@@ -54,7 +54,9 @@
                         style="@style/wifi_item_edit_content"
                         android:hint="@string/wifi_ssid_hint"
                         android:singleLine="true"
-                        android:inputType="textNoSuggestions" />
+                        android:inputType="textNoSuggestions">
+                    <requestFocus/>
+                </EditText>
 
                 <LinearLayout android:id="@+id/ssid_too_long_warning"
                               android:layout_width="match_parent"
diff --git a/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java b/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java
index 5e12503..a5f06a5 100755
--- a/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java
+++ b/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java
@@ -505,10 +505,12 @@
         mDisableAfterUninstall = andDisable;
     }
 
-    public static void startAppInfoFragment(Class<?> fragment, int title,
+    public static void startAppInfoFragment(Class<?> fragment, int title, Bundle args,
             SettingsPreferenceFragment caller, AppEntry appEntry) {
         // start new fragment to display extended information
-        final Bundle args = new Bundle();
+        if (args == null) {
+            args = new Bundle();
+        }
         args.putString(ARG_PACKAGE_NAME, appEntry.info.packageName);
         args.putInt(ARG_PACKAGE_UID, appEntry.info.uid);
 
diff --git a/src/com/android/settings/applications/appinfo/AppInfoPreferenceControllerBase.java b/src/com/android/settings/applications/appinfo/AppInfoPreferenceControllerBase.java
index 105a01e..fd545a7 100644
--- a/src/com/android/settings/applications/appinfo/AppInfoPreferenceControllerBase.java
+++ b/src/com/android/settings/applications/appinfo/AppInfoPreferenceControllerBase.java
@@ -17,6 +17,7 @@
 package com.android.settings.applications.appinfo;
 
 import android.content.Context;
+import android.os.Bundle;
 import android.support.v7.preference.Preference;
 import android.support.v7.preference.PreferenceScreen;
 import android.text.TextUtils;
@@ -58,7 +59,7 @@
     public boolean handlePreferenceTreeClick(Preference preference) {
         if (TextUtils.equals(preference.getKey(), mPreferenceKey) && mDetailFragmenClass != null) {
             AppInfoDashboardFragment.startAppInfoFragment(
-                    mDetailFragmenClass, -1, mParent, mParent.getAppEntry());
+                    mDetailFragmenClass, -1, getArguments(), mParent, mParent.getAppEntry());
             return true;
         }
         return false;
@@ -77,4 +78,12 @@
         return null;
     }
 
+    /**
+     * Gets any extras that should be passed to the fragment class when the preference is clicked.
+     * @return a bundle of extras to include in the launch intent
+     */
+    protected Bundle getArguments() {
+        return null;
+    }
+
 }
diff --git a/src/com/android/settings/applications/appinfo/AppNotificationPreferenceController.java b/src/com/android/settings/applications/appinfo/AppNotificationPreferenceController.java
index 1f19504..5a970f6 100644
--- a/src/com/android/settings/applications/appinfo/AppNotificationPreferenceController.java
+++ b/src/com/android/settings/applications/appinfo/AppNotificationPreferenceController.java
@@ -16,7 +16,10 @@
 
 package com.android.settings.applications.appinfo;
 
+import static com.android.settings.SettingsActivity.EXTRA_FRAGMENT_ARG_KEY;
+
 import android.content.Context;
+import android.os.Bundle;
 import android.support.v7.preference.Preference;
 
 import com.android.settings.SettingsPreferenceFragment;
@@ -27,12 +30,17 @@
 public class AppNotificationPreferenceController extends AppInfoPreferenceControllerBase {
 
     private static final String KEY_NOTIFICATION = "notification_settings";
+    private String mChannelId = null;
 
     // Used for updating notification preference.
     private final NotificationBackend mBackend = new NotificationBackend();
 
     public AppNotificationPreferenceController(Context context, AppInfoDashboardFragment parent) {
         super(context, parent, KEY_NOTIFICATION);
+        if (parent != null && parent.getActivity() != null
+                && parent.getActivity().getIntent() != null) {
+            mChannelId = parent.getActivity().getIntent().getStringExtra(EXTRA_FRAGMENT_ARG_KEY);
+        }
     }
 
     @Override
@@ -45,6 +53,16 @@
         return AppNotificationSettings.class;
     }
 
+    @Override
+    protected Bundle getArguments() {
+        Bundle bundle = null;
+        if (mChannelId != null) {
+            bundle = new Bundle();
+            bundle.putString(EXTRA_FRAGMENT_ARG_KEY, mChannelId);
+        }
+        return bundle;
+    }
+
     private CharSequence getNotificationSummary(ApplicationsState.AppEntry appEntry,
             Context context, NotificationBackend backend) {
         NotificationBackend.AppRow appRow =
diff --git a/src/com/android/settings/datausage/UnrestrictedDataAccess.java b/src/com/android/settings/datausage/UnrestrictedDataAccess.java
index 2e20406..83ff755 100644
--- a/src/com/android/settings/datausage/UnrestrictedDataAccess.java
+++ b/src/com/android/settings/datausage/UnrestrictedDataAccess.java
@@ -285,6 +285,7 @@
                 // app is blacklisted, launch App Data Usage screen
                 AppInfoDashboardFragment.startAppInfoFragment(AppDataUsage.class,
                     R.string.app_data_usage,
+                    null /* arguments */,
                     UnrestrictedDataAccess.this,
                     mEntry);
             } else {
diff --git a/src/com/android/settings/fuelgauge/batterytip/BatteryDatabaseManager.java b/src/com/android/settings/fuelgauge/batterytip/BatteryDatabaseManager.java
index 2019b9d..87c2488 100644
--- a/src/com/android/settings/fuelgauge/batterytip/BatteryDatabaseManager.java
+++ b/src/com/android/settings/fuelgauge/batterytip/BatteryDatabaseManager.java
@@ -38,14 +38,26 @@
 
 /**
  * Database manager for battery data. Now it only contains anomaly data stored in {@link AppInfo}.
+ *
+ * This manager may be accessed by multi-threads. All the database related methods are synchronized
+ * so each operation won't be interfered by other threads.
  */
 public class BatteryDatabaseManager {
-    private final AnomalyDatabaseHelper mDatabaseHelper;
+    private static BatteryDatabaseManager sSingleton;
 
-    public BatteryDatabaseManager(Context context) {
+    private AnomalyDatabaseHelper mDatabaseHelper;
+
+    private BatteryDatabaseManager(Context context) {
         mDatabaseHelper = AnomalyDatabaseHelper.getInstance(context);
     }
 
+    public static BatteryDatabaseManager getInstance(Context context) {
+        if (sSingleton == null) {
+            sSingleton = new BatteryDatabaseManager(context);
+        }
+        return sSingleton;
+    }
+
     /**
      * Insert an anomaly log to database.
      *
@@ -53,7 +65,7 @@
      * @param type        the type of the anomaly
      * @param timestampMs the time when it is happened
      */
-    public void insertAnomaly(String packageName, int type, long timestampMs) {
+    public synchronized void insertAnomaly(String packageName, int type, long timestampMs) {
         try (SQLiteDatabase db = mDatabaseHelper.getWritableDatabase()) {
             ContentValues values = new ContentValues();
             values.put(PACKAGE_NAME, packageName);
@@ -67,7 +79,7 @@
     /**
      * Query all the anomalies that happened after {@code timestampMsAfter} and with {@code state}.
      */
-    public List<AppInfo> queryAllAnomalies(long timestampMsAfter, int state) {
+    public synchronized List<AppInfo> queryAllAnomalies(long timestampMsAfter, int state) {
         final List<AppInfo> appInfos = new ArrayList<>();
         try (SQLiteDatabase db = mDatabaseHelper.getReadableDatabase()) {
             final String[] projection = {PACKAGE_NAME, ANOMALY_TYPE};
@@ -90,7 +102,7 @@
         return appInfos;
     }
 
-    public void deleteAllAnomaliesBeforeTimeStamp(long timestampMs) {
+    public synchronized void deleteAllAnomaliesBeforeTimeStamp(long timestampMs) {
         try (SQLiteDatabase db = mDatabaseHelper.getWritableDatabase()) {
             db.delete(TABLE_ANOMALY, TIME_STAMP_MS + " < ?",
                     new String[]{String.valueOf(timestampMs)});
@@ -103,7 +115,7 @@
      * @param appInfos represents the anomalies
      * @param state    which state to update to
      */
-    public void updateAnomalies(List<AppInfo> appInfos, int state) {
+    public synchronized void updateAnomalies(List<AppInfo> appInfos, int state) {
         if (!appInfos.isEmpty()) {
             final int size = appInfos.size();
             final String[] whereArgs = new String[size];
diff --git a/src/com/android/settings/fuelgauge/batterytip/actions/RestrictAppAction.java b/src/com/android/settings/fuelgauge/batterytip/actions/RestrictAppAction.java
index 886a6d5..37f4b2a 100644
--- a/src/com/android/settings/fuelgauge/batterytip/actions/RestrictAppAction.java
+++ b/src/com/android/settings/fuelgauge/batterytip/actions/RestrictAppAction.java
@@ -42,7 +42,7 @@
         super(context);
         mRestrictAppTip = tip;
         mBatteryUtils = BatteryUtils.getInstance(context);
-        mBatteryDatabaseManager = new BatteryDatabaseManager(context);
+        mBatteryDatabaseManager = BatteryDatabaseManager.getInstance(context);
     }
 
     /**
diff --git a/src/com/android/settings/fuelgauge/batterytip/detectors/RestrictAppDetector.java b/src/com/android/settings/fuelgauge/batterytip/detectors/RestrictAppDetector.java
index e3c9b9e..0bb1f17 100644
--- a/src/com/android/settings/fuelgauge/batterytip/detectors/RestrictAppDetector.java
+++ b/src/com/android/settings/fuelgauge/batterytip/detectors/RestrictAppDetector.java
@@ -43,7 +43,7 @@
 
     public RestrictAppDetector(Context context, BatteryTipPolicy policy) {
         mPolicy = policy;
-        mBatteryDatabaseManager = new BatteryDatabaseManager(context);
+        mBatteryDatabaseManager = BatteryDatabaseManager.getInstance(context);
     }
 
     @Override
diff --git a/tests/robotests/src/com/android/settings/applications/appinfo/AppInfoDashboardFragmentTest.java b/tests/robotests/src/com/android/settings/applications/appinfo/AppInfoDashboardFragmentTest.java
index d721e17..226ea38 100644
--- a/tests/robotests/src/com/android/settings/applications/appinfo/AppInfoDashboardFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/applications/appinfo/AppInfoDashboardFragmentTest.java
@@ -16,6 +16,7 @@
 
 package com.android.settings.applications.appinfo;
 
+import static com.android.settings.applications.appinfo.AppInfoDashboardFragment.ARG_PACKAGE_NAME;
 import static com.android.settings.applications.appinfo.AppInfoDashboardFragment
         .UNINSTALL_ALL_USERS_MENU;
 import static com.android.settings.applications.appinfo.AppInfoDashboardFragment.UNINSTALL_UPDATES;
@@ -23,6 +24,8 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.nullable;
 import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.doReturn;
@@ -33,18 +36,19 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
-import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.UserInfo;
+import android.os.Bundle;
 import android.os.UserManager;
 import android.view.Menu;
 import android.view.MenuItem;
 
 import com.android.settings.SettingsActivity;
+import com.android.settings.SettingsPreferenceFragment;
 import com.android.settings.TestConfig;
 import com.android.settings.testutils.SettingsRobolectricTestRunner;
 import com.android.settings.wrapper.DevicePolicyManagerWrapper;
@@ -57,6 +61,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Answers;
+import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RuntimeEnvironment;
@@ -315,4 +320,37 @@
         verify(context).unregisterReceiver(mFragment.mPackageRemovedReceiver);
     }
 
+    @Test
+    public void startAppInfoFragment_noCrashOnNullArgs() {
+        final SettingsPreferenceFragment caller = mock(SettingsPreferenceFragment.class);
+        final SettingsActivity sa = mock (SettingsActivity.class);
+        when(caller.getActivity()).thenReturn(sa);
+        final AppEntry appEntry = mock(AppEntry.class);
+        appEntry.info = mock(ApplicationInfo.class);
+
+        AppInfoDashboardFragment.startAppInfoFragment(AppInfoDashboardFragment.class, 0, null,
+                caller, appEntry);
+    }
+
+    @Test
+    public void startAppInfoFragment_includesNewAndOldArgs() {
+        final SettingsPreferenceFragment caller = mock(SettingsPreferenceFragment.class);
+        final SettingsActivity sa = mock (SettingsActivity.class);
+        when(caller.getActivity()).thenReturn(sa);
+        final AppEntry appEntry = mock(AppEntry.class);
+        appEntry.info = mock(ApplicationInfo.class);
+
+        final Bundle bundle = new Bundle();
+        bundle.putString("test", "test");
+
+        AppInfoDashboardFragment.startAppInfoFragment(AppInfoDashboardFragment.class, 0, bundle,
+                caller, appEntry);
+
+        final ArgumentCaptor<Bundle> captor = ArgumentCaptor.forClass(Bundle.class);
+        verify(sa).startPreferencePanel(any(), anyString(), captor.capture(), anyInt(), any(),
+                any(), anyInt());
+
+        assertThat(captor.getValue().containsKey("test"));
+        assertThat(captor.getValue().containsKey(ARG_PACKAGE_NAME));
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/applications/appinfo/AppInfoPreferenceControllerBaseTest.java b/tests/robotests/src/com/android/settings/applications/appinfo/AppInfoPreferenceControllerBaseTest.java
index 51b6ddf..0c80ef4 100644
--- a/tests/robotests/src/com/android/settings/applications/appinfo/AppInfoPreferenceControllerBaseTest.java
+++ b/tests/robotests/src/com/android/settings/applications/appinfo/AppInfoPreferenceControllerBaseTest.java
@@ -26,6 +26,7 @@
 import static org.mockito.Mockito.when;
 
 import android.content.pm.ApplicationInfo;
+import android.os.Bundle;
 import android.support.v7.preference.Preference;
 import android.support.v7.preference.PreferenceScreen;
 
@@ -39,6 +40,7 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RuntimeEnvironment;
@@ -90,9 +92,12 @@
 
         mController.handlePreferenceTreeClick(mPreference);
 
+        ArgumentCaptor<Bundle> captor = ArgumentCaptor.forClass(Bundle.class);
         verify(mActivity).startPreferencePanel(any(),
-                eq(mController.getDetailFragmentClass().getName()), any(), anyInt(), any(), any(),
-                anyInt());
+                eq(mController.getDetailFragmentClass().getName()), captor.capture(), anyInt(),
+                any(), any(), anyInt());
+
+        assertThat(captor.getValue().containsKey("test"));
     }
 
     private class TestPreferenceController extends AppInfoPreferenceControllerBase {
@@ -113,6 +118,13 @@
             return AppNotificationSettings.class;
         }
 
+        @Override
+        protected Bundle getArguments() {
+            Bundle bundle = new Bundle();
+            bundle.putString("test", "test");
+            return bundle;
+        }
+
     }
 
 }
diff --git a/tests/robotests/src/com/android/settings/applications/appinfo/AppNotificationPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/applications/appinfo/AppNotificationPreferenceControllerTest.java
index 0b747a8..8dc47f8 100644
--- a/tests/robotests/src/com/android/settings/applications/appinfo/AppNotificationPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/applications/appinfo/AppNotificationPreferenceControllerTest.java
@@ -16,6 +16,8 @@
 
 package com.android.settings.applications.appinfo;
 
+import static com.android.settings.SettingsActivity.EXTRA_FRAGMENT_ARG_KEY;
+
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.ArgumentMatchers.any;
@@ -24,7 +26,9 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.app.Activity;
 import android.content.Context;
+import android.content.Intent;
 import android.content.pm.ApplicationInfo;
 import android.support.v7.preference.Preference;
 import android.support.v7.preference.PreferenceScreen;
@@ -87,4 +91,22 @@
         verify(mPreference).setSummary(any());
     }
 
+    @Test
+    public void getArguments_nullIfChannelIsNull() {
+        assertThat(mController.getArguments()).isNull();
+    }
+
+    @Test
+    public void getArguments_containsChannelId() {
+        Activity activity = mock(Activity.class);
+        Intent intent = new Intent();
+        intent.putExtra(EXTRA_FRAGMENT_ARG_KEY, "test");
+        when(mFragment.getActivity()).thenReturn(activity);
+        when(activity.getIntent()).thenReturn(intent);
+        AppNotificationPreferenceController controller =
+                new AppNotificationPreferenceController(mContext, mFragment);
+
+        assertThat(controller.getArguments().containsKey(EXTRA_FRAGMENT_ARG_KEY)).isTrue();
+        assertThat(controller.getArguments().getString(EXTRA_FRAGMENT_ARG_KEY)).isEqualTo("test");
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryDatabaseManagerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryDatabaseManagerTest.java
index 92332f2..e835e65 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryDatabaseManagerTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryDatabaseManagerTest.java
@@ -59,7 +59,7 @@
         MockitoAnnotations.initMocks(this);
 
         mContext = RuntimeEnvironment.application;
-        mBatteryDatabaseManager = spy(new BatteryDatabaseManager(mContext));
+        mBatteryDatabaseManager = spy(BatteryDatabaseManager.getInstance(mContext));
     }
 
     @After
diff --git a/tests/robotests/src/com/android/settings/testutils/DatabaseTestUtils.java b/tests/robotests/src/com/android/settings/testutils/DatabaseTestUtils.java
index 499a2f7..2ffdc60 100644
--- a/tests/robotests/src/com/android/settings/testutils/DatabaseTestUtils.java
+++ b/tests/robotests/src/com/android/settings/testutils/DatabaseTestUtils.java
@@ -19,6 +19,7 @@
 import android.content.Context;
 
 import com.android.settings.fuelgauge.batterytip.AnomalyDatabaseHelper;
+import com.android.settings.fuelgauge.batterytip.BatteryDatabaseManager;
 import com.android.settings.search.IndexDatabaseHelper;
 import com.android.settings.slices.SlicesDatabaseHelper;
 
@@ -30,6 +31,7 @@
         clearSearchDb(context);
         clearSlicesDb(context);
         clearAnomalyDb(context);
+        clearAnomalyDbManager();
     }
 
     private static void clearSlicesDb(Context context) {
@@ -76,4 +78,16 @@
             throw new RuntimeException();
         }
     }
+
+    private static void clearAnomalyDbManager() {
+        Field instance;
+        Class clazz = BatteryDatabaseManager.class;
+        try {
+            instance = clazz.getDeclaredField("sSingleton");
+            instance.setAccessible(true);
+            instance.set(null, null);
+        } catch (Exception e) {
+            throw new RuntimeException();
+        }
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/wifi/WifiConfigControllerTest.java b/tests/robotests/src/com/android/settings/wifi/WifiConfigControllerTest.java
index e9b6146..b200639 100644
--- a/tests/robotests/src/com/android/settings/wifi/WifiConfigControllerTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/WifiConfigControllerTest.java
@@ -199,6 +199,15 @@
         assertThat(mView.findViewById(R.id.eap).getVisibility()).isEqualTo(View.GONE);
     }
 
+    @Test
+    public void ssidGetFocus_addNewNetwork_shouldReturnTrue() {
+        mController = new TestWifiConfigController(mConfigUiBase, mView, null /* accessPoint */,
+                WifiConfigUiBase.MODE_CONNECT);
+        final TextView ssid = mView.findViewById(R.id.ssid);
+        // Verify ssid text get focus when add new network
+        assertThat(ssid.isFocused()).isTrue();
+    }
+
     public class TestWifiConfigController extends WifiConfigController {
 
         public TestWifiConfigController(WifiConfigUiBase parent, View view,