diff --git a/Android.mk b/Android.mk
index e5a712f191..28f0bc23bc 100644
--- a/Android.mk
+++ b/Android.mk
@@ -108,7 +108,9 @@ include $(CLEAR_VARS)
LOCAL_USE_AAPT2 := true
LOCAL_MODULE_TAGS := optional
-LOCAL_STATIC_ANDROID_LIBRARIES := Launcher3CommonDepsLib
+LOCAL_STATIC_ANDROID_LIBRARIES := \
+ Launcher3CommonDepsLib \
+ SecondaryDisplayLauncherLib
LOCAL_SRC_FILES := \
$(call all-java-files-under, src) \
$(call all-java-files-under, src_shortcuts_overrides) \
diff --git a/SecondaryDisplayLauncher/Android.mk b/SecondaryDisplayLauncher/Android.mk
new file mode 100644
index 0000000000..4fb5eba172
--- /dev/null
+++ b/SecondaryDisplayLauncher/Android.mk
@@ -0,0 +1,39 @@
+#
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_USE_AAPT2 := true
+LOCAL_AAPT2_ONLY := true
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_STATIC_ANDROID_LIBRARIES := androidx.design_design
+
+LOCAL_STATIC_JAVA_LIBRARIES := LauncherPluginLib
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+
+LOCAL_PROGUARD_ENABLED := disabled
+
+LOCAL_SDK_VERSION := current
+LOCAL_MIN_SDK_VERSION := 21
+LOCAL_MODULE := SecondaryDisplayLauncherLib
+LOCAL_PRIVILEGED_MODULE := true
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/SecondaryDisplayLauncher/AndroidManifest.xml b/SecondaryDisplayLauncher/AndroidManifest.xml
new file mode 100644
index 0000000000..ebf6b02cb8
--- /dev/null
+++ b/SecondaryDisplayLauncher/AndroidManifest.xml
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/SecondaryDisplayLauncher/res/drawable/ic_apps.xml b/SecondaryDisplayLauncher/res/drawable/ic_apps.xml
new file mode 100644
index 0000000000..db779c2d12
--- /dev/null
+++ b/SecondaryDisplayLauncher/res/drawable/ic_apps.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
diff --git a/SecondaryDisplayLauncher/res/drawable/ic_settings.xml b/SecondaryDisplayLauncher/res/drawable/ic_settings.xml
new file mode 100644
index 0000000000..c269c3bafc
--- /dev/null
+++ b/SecondaryDisplayLauncher/res/drawable/ic_settings.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
diff --git a/SecondaryDisplayLauncher/res/layout-sw600dp/secondary_display_launcher.xml b/SecondaryDisplayLauncher/res/layout-sw600dp/secondary_display_launcher.xml
new file mode 100644
index 0000000000..46f1674e47
--- /dev/null
+++ b/SecondaryDisplayLauncher/res/layout-sw600dp/secondary_display_launcher.xml
@@ -0,0 +1,56 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/SecondaryDisplayLauncher/res/layout-sw720dp/secondary_display_launcher.xml b/SecondaryDisplayLauncher/res/layout-sw720dp/secondary_display_launcher.xml
new file mode 100644
index 0000000000..6653a77968
--- /dev/null
+++ b/SecondaryDisplayLauncher/res/layout-sw720dp/secondary_display_launcher.xml
@@ -0,0 +1,57 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/SecondaryDisplayLauncher/res/layout/app_grid_item.xml b/SecondaryDisplayLauncher/res/layout/app_grid_item.xml
new file mode 100644
index 0000000000..ee5158ad32
--- /dev/null
+++ b/SecondaryDisplayLauncher/res/layout/app_grid_item.xml
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+
diff --git a/SecondaryDisplayLauncher/res/layout/app_picker_dialog.xml b/SecondaryDisplayLauncher/res/layout/app_picker_dialog.xml
new file mode 100644
index 0000000000..563a1afa78
--- /dev/null
+++ b/SecondaryDisplayLauncher/res/layout/app_picker_dialog.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
diff --git a/SecondaryDisplayLauncher/res/layout/app_picker_layout.xml b/SecondaryDisplayLauncher/res/layout/app_picker_layout.xml
new file mode 100644
index 0000000000..fbaeac4605
--- /dev/null
+++ b/SecondaryDisplayLauncher/res/layout/app_picker_layout.xml
@@ -0,0 +1,46 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/SecondaryDisplayLauncher/res/layout/secondary_display_launcher.xml b/SecondaryDisplayLauncher/res/layout/secondary_display_launcher.xml
new file mode 100644
index 0000000000..49cd499a50
--- /dev/null
+++ b/SecondaryDisplayLauncher/res/layout/secondary_display_launcher.xml
@@ -0,0 +1,56 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/SecondaryDisplayLauncher/res/menu/context_menu.xml b/SecondaryDisplayLauncher/res/menu/context_menu.xml
new file mode 100644
index 0000000000..626384229e
--- /dev/null
+++ b/SecondaryDisplayLauncher/res/menu/context_menu.xml
@@ -0,0 +1,23 @@
+
+
+
+
diff --git a/SecondaryDisplayLauncher/res/values-sw600dp/dimens.xml b/SecondaryDisplayLauncher/res/values-sw600dp/dimens.xml
new file mode 100644
index 0000000000..f33a8db400
--- /dev/null
+++ b/SecondaryDisplayLauncher/res/values-sw600dp/dimens.xml
@@ -0,0 +1,22 @@
+
+
+
+
+ 400dp
+ 400dp
+ 60dp
+
diff --git a/SecondaryDisplayLauncher/res/values-sw720dp/dimens.xml b/SecondaryDisplayLauncher/res/values-sw720dp/dimens.xml
new file mode 100644
index 0000000000..524e52af71
--- /dev/null
+++ b/SecondaryDisplayLauncher/res/values-sw720dp/dimens.xml
@@ -0,0 +1,22 @@
+
+
+
+
+ 660dp
+ 660dp
+ 70dp
+
diff --git a/SecondaryDisplayLauncher/res/values/colors.xml b/SecondaryDisplayLauncher/res/values/colors.xml
new file mode 100644
index 0000000000..66b41a2ba6
--- /dev/null
+++ b/SecondaryDisplayLauncher/res/values/colors.xml
@@ -0,0 +1,22 @@
+
+
+
+ #884e8391
+
diff --git a/SecondaryDisplayLauncher/res/values/dimens.xml b/SecondaryDisplayLauncher/res/values/dimens.xml
new file mode 100644
index 0000000000..7cca60719c
--- /dev/null
+++ b/SecondaryDisplayLauncher/res/values/dimens.xml
@@ -0,0 +1,31 @@
+
+
+
+
+ 72dp
+ 24dp
+ 24dp
+ 64dp
+ 64dp
+ 24dp
+ 8dp
+ 8dp
+
+ 300dp
+ 300dp
+ 20dp
+ 20dp
+
diff --git a/SecondaryDisplayLauncher/res/values/strings.xml b/SecondaryDisplayLauncher/res/values/strings.xml
new file mode 100644
index 0000000000..0f906c4837
--- /dev/null
+++ b/SecondaryDisplayLauncher/res/values/strings.xml
@@ -0,0 +1,25 @@
+
+
+
+
+ SecondaryDisplayLauncher
+ Couldn\'t launch the activity
+ Add app shortcut
+ Set wallpaper
+
diff --git a/SecondaryDisplayLauncher/res/values/styles.xml b/SecondaryDisplayLauncher/res/values/styles.xml
new file mode 100644
index 0000000000..4bfda6a2a5
--- /dev/null
+++ b/SecondaryDisplayLauncher/res/values/styles.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
diff --git a/SecondaryDisplayLauncher/src/com/android/launcher3/AppEntry.java b/SecondaryDisplayLauncher/src/com/android/launcher3/AppEntry.java
new file mode 100644
index 0000000000..3017b81c1d
--- /dev/null
+++ b/SecondaryDisplayLauncher/src/com/android/launcher3/AppEntry.java
@@ -0,0 +1,58 @@
+/**
+ * Copyright (c) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3;
+
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.graphics.drawable.Drawable;
+
+/** An entry that represents a single activity that can be launched. */
+public class AppEntry {
+
+ private String mLabel;
+ private Drawable mIcon;
+ private Intent mLaunchIntent;
+
+ AppEntry(ResolveInfo info, PackageManager packageManager) {
+ mLabel = info.loadLabel(packageManager).toString();
+ mIcon = info.loadIcon(packageManager);
+ mLaunchIntent = new Intent();
+ mLaunchIntent.setComponent(new ComponentName(info.activityInfo.packageName,
+ info.activityInfo.name));
+ }
+
+ String getLabel() {
+ return mLabel;
+ }
+
+ Drawable getIcon() {
+ return mIcon;
+ }
+
+ Intent getLaunchIntent() { return mLaunchIntent; }
+
+ ComponentName getComponentName() {
+ return mLaunchIntent.getComponent();
+ }
+
+ @Override
+ public String toString() {
+ return mLabel;
+ }
+}
diff --git a/SecondaryDisplayLauncher/src/com/android/launcher3/AppListAdapter.java b/SecondaryDisplayLauncher/src/com/android/launcher3/AppListAdapter.java
new file mode 100644
index 0000000000..aa115cb575
--- /dev/null
+++ b/SecondaryDisplayLauncher/src/com/android/launcher3/AppListAdapter.java
@@ -0,0 +1,63 @@
+/**
+ * Copyright (c) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.android.launcher3.R;
+
+import java.util.List;
+
+/** Adapter for available apps list. */
+public class AppListAdapter extends ArrayAdapter {
+ private final LayoutInflater mInflater;
+
+ AppListAdapter(Context context) {
+ super(context, android.R.layout.simple_list_item_2);
+ mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ }
+
+ void setData(List data) {
+ clear();
+ if (data != null) {
+ addAll(data);
+ }
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ View view;
+
+ if (convertView == null) {
+ view = mInflater.inflate(R.layout.app_grid_item, parent, false);
+ } else {
+ view = convertView;
+ }
+
+ AppEntry item = getItem(position);
+ ((ImageView)view.findViewById(R.id.app_icon)).setImageDrawable(item.getIcon());
+ ((TextView)view.findViewById(R.id.app_name)).setText(item.getLabel());
+
+ return view;
+ }
+}
diff --git a/SecondaryDisplayLauncher/src/com/android/launcher3/AppListViewModel.java b/SecondaryDisplayLauncher/src/com/android/launcher3/AppListViewModel.java
new file mode 100644
index 0000000000..914fd5e01a
--- /dev/null
+++ b/SecondaryDisplayLauncher/src/com/android/launcher3/AppListViewModel.java
@@ -0,0 +1,126 @@
+/**
+ * Copyright (c) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3;
+
+import android.app.Application;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.os.AsyncTask;
+
+import androidx.lifecycle.AndroidViewModel;
+import androidx.lifecycle.LiveData;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A view model that provides a list of activities that can be launched.
+ */
+public class AppListViewModel extends AndroidViewModel {
+
+ private final AppListLiveData mLiveData;
+ private final PackageIntentReceiver
+ mPackageIntentReceiver;
+
+ public AppListViewModel(Application application) {
+ super(application);
+ mLiveData = new AppListLiveData(application);
+ mPackageIntentReceiver = new PackageIntentReceiver(mLiveData, application);
+ }
+
+ public LiveData> getAppList() {
+ return mLiveData;
+ }
+
+ protected void onCleared() {
+ getApplication().unregisterReceiver(mPackageIntentReceiver);
+ }
+}
+
+class AppListLiveData extends LiveData> {
+
+ private final PackageManager mPackageManager;
+ private int mCurrentDataVersion;
+
+ public AppListLiveData(Context context) {
+ mPackageManager = context.getPackageManager();
+ loadData();
+ }
+
+ void loadData() {
+ final int loadDataVersion = ++mCurrentDataVersion;
+
+ new AsyncTask>() {
+ @Override
+ protected List doInBackground(Void... voids) {
+ Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
+ mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
+
+ List apps = mPackageManager.queryIntentActivities(mainIntent,
+ PackageManager.GET_META_DATA);
+
+ List entries = new ArrayList<>();
+ if (apps != null) {
+ for (ResolveInfo app : apps) {
+ AppEntry entry = new AppEntry(app, mPackageManager);
+ entries.add(entry);
+ }
+ }
+ return entries;
+ }
+
+ @Override
+ protected void onPostExecute(List data) {
+ if (mCurrentDataVersion == loadDataVersion) {
+ setValue(data);
+ }
+ }
+ }.execute();
+ }
+}
+
+/**
+ * Receiver used to notify live data about app list changes.
+ */
+class PackageIntentReceiver extends BroadcastReceiver {
+
+ private final AppListLiveData mLiveData;
+
+ public PackageIntentReceiver(AppListLiveData liveData, Context context) {
+ mLiveData = liveData;
+ IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
+ filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+ filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
+ filter.addDataScheme("package");
+ context.registerReceiver(this, filter);
+
+ // Register for events related to sdcard installation.
+ IntentFilter sdFilter = new IntentFilter();
+ sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
+ sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
+ context.registerReceiver(this, sdFilter);
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ mLiveData.loadData();
+ }
+}
\ No newline at end of file
diff --git a/SecondaryDisplayLauncher/src/com/android/launcher3/PinnedAppListViewModel.java b/SecondaryDisplayLauncher/src/com/android/launcher3/PinnedAppListViewModel.java
new file mode 100644
index 0000000000..4f92038ae4
--- /dev/null
+++ b/SecondaryDisplayLauncher/src/com/android/launcher3/PinnedAppListViewModel.java
@@ -0,0 +1,120 @@
+/**
+ * Copyright (c) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3;
+
+import static com.android.launcher3.PinnedAppListViewModel.PINNED_APPS_KEY;
+
+import android.app.Application;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.os.AsyncTask;
+
+import androidx.lifecycle.AndroidViewModel;
+import androidx.lifecycle.LiveData;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * A view model that provides a list of activities that were pinned by user to always display on
+ * home screen.
+ * The pinned activities are stored in {@link SharedPreferences} to keep the sample simple :).
+ */
+public class PinnedAppListViewModel extends AndroidViewModel {
+
+ final static String PINNED_APPS_KEY = "pinned_apps";
+
+ private final PinnedAppListLiveData mLiveData;
+
+ public PinnedAppListViewModel(Application application) {
+ super(application);
+ mLiveData = new PinnedAppListLiveData(application);
+ }
+
+ public LiveData> getPinnedAppList() {
+ return mLiveData;
+ }
+}
+
+class PinnedAppListLiveData extends LiveData> {
+
+ private final Context mContext;
+ private final PackageManager mPackageManager;
+ // Store listener reference, so it won't be GC-ed.
+ private final SharedPreferences.OnSharedPreferenceChangeListener mChangeListener;
+ private int mCurrentDataVersion;
+
+ public PinnedAppListLiveData(Context context) {
+ mContext = context;
+ mPackageManager = context.getPackageManager();
+
+ final SharedPreferences prefs = context.getSharedPreferences(PINNED_APPS_KEY, 0);
+ mChangeListener = (preferences, key) -> {
+ loadData();
+ };
+ prefs.registerOnSharedPreferenceChangeListener(mChangeListener);
+
+ loadData();
+ }
+
+ private void loadData() {
+ final int loadDataVersion = ++mCurrentDataVersion;
+
+ new AsyncTask>() {
+ @Override
+ protected List doInBackground(Void... voids) {
+ List entries = new ArrayList<>();
+
+ final SharedPreferences sp = mContext.getSharedPreferences(PINNED_APPS_KEY, 0);
+ final Set pinnedAppsComponents = sp.getStringSet(PINNED_APPS_KEY, null);
+ if (pinnedAppsComponents == null) {
+ return null;
+ }
+
+ for (String componentString : pinnedAppsComponents) {
+ final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
+ mainIntent.setComponent(ComponentName.unflattenFromString(componentString));
+ mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
+
+ final List apps = mPackageManager.queryIntentActivities(mainIntent,
+ PackageManager.GET_META_DATA);
+
+ if (apps != null) {
+ for (ResolveInfo app : apps) {
+ final AppEntry entry = new AppEntry(app, mPackageManager);
+ entries.add(entry);
+ }
+ }
+ }
+
+ return entries;
+ }
+
+ @Override
+ protected void onPostExecute(List data) {
+ if (mCurrentDataVersion == loadDataVersion) {
+ setValue(data);
+ }
+ }
+ }.execute();
+ }
+}
\ No newline at end of file
diff --git a/SecondaryDisplayLauncher/src/com/android/launcher3/PinnedAppPickerDialog.java b/SecondaryDisplayLauncher/src/com/android/launcher3/PinnedAppPickerDialog.java
new file mode 100644
index 0000000000..02e6e4a9c6
--- /dev/null
+++ b/SecondaryDisplayLauncher/src/com/android/launcher3/PinnedAppPickerDialog.java
@@ -0,0 +1,74 @@
+/**
+ * Copyright (c) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3;
+
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.GridView;
+
+import androidx.fragment.app.DialogFragment;
+
+import com.android.launcher3.R;
+
+/**
+ * Callback to be invoked when an app was picked.
+ */
+interface AppPickedCallback {
+ void onAppPicked(AppEntry appEntry);
+}
+
+/**
+ * Dialog that provides the user with a list of available apps to pin to the home screen.
+ */
+public class PinnedAppPickerDialog extends DialogFragment {
+
+ private AppListAdapter mAppListAdapter;
+ private AppPickedCallback mAppPickerCallback;
+
+ public PinnedAppPickerDialog() {
+ }
+
+ public static PinnedAppPickerDialog newInstance(AppListAdapter appListAdapter,
+ AppPickedCallback callback) {
+ PinnedAppPickerDialog
+ frag = new PinnedAppPickerDialog();
+ frag.mAppListAdapter = appListAdapter;
+ frag.mAppPickerCallback = callback;
+ return frag;
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ return inflater.inflate(R.layout.app_picker_dialog, container);
+ }
+
+ @Override
+ public void onViewCreated(View view, Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+
+ GridView appGridView = view.findViewById(R.id.picker_app_grid);
+ appGridView.setAdapter(mAppListAdapter);
+ appGridView.setOnItemClickListener((adapterView, itemView, position, id) -> {
+ final AppEntry entry = mAppListAdapter.getItem(position);
+ mAppPickerCallback.onAppPicked(entry);
+ dismiss();
+ });
+ }
+}
\ No newline at end of file
diff --git a/SecondaryDisplayLauncher/src/com/android/launcher3/SecondaryDisplayLauncher.java b/SecondaryDisplayLauncher/src/com/android/launcher3/SecondaryDisplayLauncher.java
new file mode 100644
index 0000000000..5e8b40246a
--- /dev/null
+++ b/SecondaryDisplayLauncher/src/com/android/launcher3/SecondaryDisplayLauncher.java
@@ -0,0 +1,217 @@
+/**
+ * Copyright (c) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3;
+
+import static com.android.launcher3.PinnedAppListViewModel.PINNED_APPS_KEY;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.app.AlertDialog;
+import android.app.Application;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.res.Configuration;
+import android.os.Bundle;
+import android.support.design.circularreveal.cardview.CircularRevealCardView;
+import android.support.design.widget.FloatingActionButton;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewAnimationUtils;
+import android.widget.GridView;
+import android.widget.ImageButton;
+import android.widget.PopupMenu;
+
+import androidx.fragment.app.FragmentActivity;
+import androidx.fragment.app.FragmentManager;
+import androidx.lifecycle.ViewModelProvider;
+import androidx.lifecycle.ViewModelProvider.AndroidViewModelFactory;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Secondary launcher activity. It's launch mode is configured as "singleTop" to allow showing on
+ * multiple displays and to ensure a single instance per each display.
+ */
+public class SecondaryDisplayLauncher extends FragmentActivity implements AppPickedCallback,
+ PopupMenu.OnMenuItemClickListener {
+
+ private AppListAdapter mAppListAdapter;
+ private AppListAdapter mPinnedAppListAdapter;
+ private CircularRevealCardView mAppDrawerView;
+ private FloatingActionButton mFab;
+
+ private boolean mAppDrawerShown;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.secondary_display_launcher);
+
+ mAppDrawerView = findViewById(R.id.FloatingSheet);
+ mFab = findViewById(R.id.FloatingActionButton);
+
+ mFab.setOnClickListener((View v) -> {
+ showAppDrawer(true);
+ });
+
+ final ViewModelProvider viewModelProvider = new ViewModelProvider(getViewModelStore(),
+ new AndroidViewModelFactory((Application) getApplicationContext()));
+
+ mPinnedAppListAdapter = new AppListAdapter(this);
+ final GridView pinnedAppGridView = findViewById(R.id.pinned_app_grid);
+ pinnedAppGridView.setAdapter(mPinnedAppListAdapter);
+ pinnedAppGridView.setOnItemClickListener((adapterView, view, position, id) -> {
+ final AppEntry entry = mPinnedAppListAdapter.getItem(position);
+ launch(entry.getLaunchIntent());
+ });
+ final PinnedAppListViewModel pinnedAppListViewModel =
+ viewModelProvider.get(PinnedAppListViewModel.class);
+ pinnedAppListViewModel.getPinnedAppList().observe(this, data -> {
+ mPinnedAppListAdapter.setData(data);
+ });
+
+ mAppListAdapter = new AppListAdapter(this);
+ final GridView appGridView = findViewById(R.id.app_grid);
+ appGridView.setAdapter(mAppListAdapter);
+ appGridView.setOnItemClickListener((adapterView, view, position, id) -> {
+ final AppEntry entry = mAppListAdapter.getItem(position);
+ launch(entry.getLaunchIntent());
+ });
+ final AppListViewModel appListViewModel = viewModelProvider.get(AppListViewModel.class);
+ appListViewModel.getAppList().observe(this, data -> {
+ mAppListAdapter.setData(data);
+ });
+
+ ImageButton optionsButton = findViewById(R.id.OptionsButton);
+ optionsButton.setOnClickListener((View v) -> {
+ PopupMenu popup = new PopupMenu(this,v);
+ popup.setOnMenuItemClickListener(this);
+ MenuInflater inflater = popup.getMenuInflater();
+ inflater.inflate(R.menu.context_menu, popup.getMenu());
+ popup.show();
+ });
+ }
+
+ @Override
+ public boolean onMenuItemClick(MenuItem item) {
+ // Respond to picking one of the popup menu items.
+ final int id = item.getItemId();
+ if (id == R.id.add_app_shortcut) {
+ FragmentManager fm = getSupportFragmentManager();
+ PinnedAppPickerDialog pickerDialogFragment =
+ PinnedAppPickerDialog.newInstance(mAppListAdapter, this);
+ pickerDialogFragment.show(fm, "fragment_app_picker");
+ return true;
+ } else if (id == R.id.set_wallpaper) {
+ Intent intent = new Intent(Intent.ACTION_SET_WALLPAPER);
+ startActivity(Intent.createChooser(intent, getString(R.string.set_wallpaper)));
+ return true;
+ }
+
+ return true;
+ }
+
+ @Override
+ public void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+ showAppDrawer(false);
+ }
+
+ public void onBackPressed() {
+ // If the app drawer was shown - hide it. Otherwise, not doing anything since we don't want
+ // to close the launcher.
+ showAppDrawer(false);
+ }
+
+ public void onNewIntent(Intent intent) {
+ super.onNewIntent(intent);
+ // A new intent will bring the launcher to top. Hide the app drawer to reset the state.
+ showAppDrawer(false);
+ }
+
+ void launch(Intent launchIntent) {
+ launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ try {
+ startActivity(launchIntent);
+ } catch (Exception e) {
+ final AlertDialog.Builder builder =
+ new AlertDialog.Builder(this, android.R.style.Theme_Material_Dialog_Alert);
+ builder.setTitle(R.string.couldnt_launch)
+ .setMessage(e.getLocalizedMessage())
+ .setIcon(android.R.drawable.ic_dialog_alert)
+ .show();
+ }
+ }
+
+ /**
+ * Store the picked app to persistent pinned list and update the loader.
+ */
+ @Override
+ public void onAppPicked(AppEntry appEntry) {
+ final SharedPreferences sp = getSharedPreferences(PINNED_APPS_KEY, 0);
+ Set pinnedApps = sp.getStringSet(PINNED_APPS_KEY, null);
+ if (pinnedApps == null) {
+ pinnedApps = new HashSet();
+ } else {
+ // Always need to create a new object to make sure that the changes are persisted.
+ pinnedApps = new HashSet(pinnedApps);
+ }
+ pinnedApps.add(appEntry.getComponentName().flattenToString());
+
+ final SharedPreferences.Editor editor = sp.edit();
+ editor.putStringSet(PINNED_APPS_KEY, pinnedApps);
+ editor.apply();
+ }
+
+ /**
+ * Show/hide app drawer card with animation.
+ */
+ private void showAppDrawer(boolean show) {
+ if (show == mAppDrawerShown) {
+ return;
+ }
+
+ final Animator animator = revealAnimator(mAppDrawerView, show);
+ if (show) {
+ mAppDrawerShown = true;
+ mAppDrawerView.setVisibility(View.VISIBLE);
+ mFab.setVisibility(View.INVISIBLE);
+ } else {
+ mAppDrawerShown = false;
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ super.onAnimationEnd(animation);
+ mAppDrawerView.setVisibility(View.INVISIBLE);
+ mFab.setVisibility(View.VISIBLE);
+ }
+ });
+ }
+ animator.start();
+ }
+
+ /**
+ * Create reveal/hide animator for app list card.
+ */
+ private Animator revealAnimator(View view, boolean open) {
+ final int radius = (int) Math.hypot((double) view.getWidth(), (double) view.getHeight());
+ return ViewAnimationUtils.createCircularReveal(view, view.getRight(), view.getBottom(),
+ open ? 0 : radius, open ? radius : 0);
+ }
+}
diff --git a/quickstep/libs/sysui_shared.jar b/quickstep/libs/sysui_shared.jar
index 5958d02029..6e7534dc6d 100644
Binary files a/quickstep/libs/sysui_shared.jar and b/quickstep/libs/sysui_shared.jar differ
diff --git a/quickstep/res/values-mr/strings.xml b/quickstep/res/values-mr/strings.xml
index f88bb77f4b..fa8574a3cf 100644
--- a/quickstep/res/values-mr/strings.xml
+++ b/quickstep/res/values-mr/strings.xml
@@ -25,7 +25,7 @@
"अवलोकन"
"कोणतेही अलीकडील आयटम नाहीत"
"बंद"
- "अॅप वापर सेटिंग्ज"
+ "अॅप वापर सेटिंग्ज"
"सर्व साफ करा"
"अलीकडील अॅप्स"
diff --git a/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java b/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java
index 1049cca597..a084ca8078 100644
--- a/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java
+++ b/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java
@@ -80,8 +80,8 @@ import com.android.systemui.shared.system.RemoteAnimationAdapterCompat;
import com.android.systemui.shared.system.RemoteAnimationDefinitionCompat;
import com.android.systemui.shared.system.RemoteAnimationRunnerCompat;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
-import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplier;
-import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplier.SurfaceParams;
+import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat;
+import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams;
import com.android.systemui.shared.system.WindowManagerWrapper;
/**
@@ -580,8 +580,8 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
MODE_OPENING);
RemoteAnimationTargetSet closingTargets = new RemoteAnimationTargetSet(targets,
MODE_CLOSING);
- SyncRtSurfaceTransactionApplier surfaceApplier = new SyncRtSurfaceTransactionApplier(
- mFloatingView);
+ SyncRtSurfaceTransactionApplierCompat surfaceApplier =
+ new SyncRtSurfaceTransactionApplierCompat(mFloatingView);
ValueAnimator appAnimator = ValueAnimator.ofFloat(0, 1);
appAnimator.setDuration(APP_LAUNCH_DURATION);
@@ -618,7 +618,7 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
// Animate window corner radius from 100% to windowCornerRadius.
float windowCornerRadius = RecentsModel.INSTANCE.get(mLauncher)
.getWindowCornerRadius();
- float circleRadius = scaledWindowWidth / 2f;
+ float circleRadius = iconWidth / 2f;
float windowRadius = Utilities.mapRange(easePercent, circleRadius,
windowCornerRadius);
@@ -740,8 +740,8 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
* Animator that controls the transformations of the windows the targets that are closing.
*/
private Animator getClosingWindowAnimators(RemoteAnimationTargetCompat[] targets) {
- SyncRtSurfaceTransactionApplier surfaceApplier =
- new SyncRtSurfaceTransactionApplier(mDragLayer);
+ SyncRtSurfaceTransactionApplierCompat surfaceApplier =
+ new SyncRtSurfaceTransactionApplierCompat(mDragLayer);
Matrix matrix = new Matrix();
ValueAnimator closingAnimator = ValueAnimator.ofFloat(0, 1);
int duration = CLOSING_TRANSITION_DURATION_MS;
diff --git a/quickstep/src/com/android/quickstep/ActivityControlHelper.java b/quickstep/src/com/android/quickstep/ActivityControlHelper.java
index 16f5fa1142..f60572cc32 100644
--- a/quickstep/src/com/android/quickstep/ActivityControlHelper.java
+++ b/quickstep/src/com/android/quickstep/ActivityControlHelper.java
@@ -45,6 +45,7 @@ import android.os.Handler;
import android.os.Looper;
import android.view.View;
+import com.android.launcher3.BaseActivity;
import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Launcher;
@@ -114,6 +115,11 @@ public interface ActivityControlHelper {
@Nullable
T getCreatedActivity();
+ default boolean isResumed() {
+ BaseDraggingActivity activity = getCreatedActivity();
+ return activity != null && activity.hasBeenResumed();
+ }
+
@UiThread
@Nullable
RecentsView getVisibleRecentsView();
diff --git a/quickstep/src/com/android/quickstep/LauncherSearchIndexablesProvider.java b/quickstep/src/com/android/quickstep/LauncherSearchIndexablesProvider.java
index f5e1f6ec56..5d6fbe2ca6 100644
--- a/quickstep/src/com/android/quickstep/LauncherSearchIndexablesProvider.java
+++ b/quickstep/src/com/android/quickstep/LauncherSearchIndexablesProvider.java
@@ -29,7 +29,6 @@ import android.provider.SearchIndexablesProvider;
import android.util.Xml;
import com.android.launcher3.R;
-import com.android.launcher3.graphics.IconShapeOverride;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -88,8 +87,6 @@ public class LauncherSearchIndexablesProvider extends SearchIndexablesProvider {
} catch (IOException |XmlPullParserException e) {
throw new RuntimeException(e);
}
- } else if (!IconShapeOverride.isSupported(getContext())) {
- cursor.addRow(new String[] {IconShapeOverride.KEY_PREFERENCE});
}
return cursor;
}
diff --git a/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java b/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java
index b11260ea58..95be188a0e 100644
--- a/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java
+++ b/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java
@@ -22,6 +22,8 @@ import static android.view.MotionEvent.ACTION_POINTER_UP;
import static android.view.MotionEvent.ACTION_UP;
import static android.view.MotionEvent.INVALID_POINTER_ID;
+import static com.android.launcher3.util.RaceConditionTracker.ENTER;
+import static com.android.launcher3.util.RaceConditionTracker.EXIT;
import static com.android.systemui.shared.system.ActivityManagerWrapper
.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS;
import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING;
@@ -47,6 +49,7 @@ import android.view.ViewConfiguration;
import android.view.WindowManager;
import com.android.launcher3.MainThreadExecutor;
+import com.android.launcher3.util.RaceConditionTracker;
import com.android.launcher3.util.TraceHelper;
import com.android.quickstep.util.RemoteAnimationTargetSet;
import com.android.systemui.shared.system.ActivityManagerWrapper;
@@ -70,6 +73,7 @@ import java.util.concurrent.TimeUnit;
public class OtherActivityTouchConsumer extends ContextWrapper implements TouchConsumer {
private static final long LAUNCHER_DRAW_TIMEOUT_MS = 150;
+ public static final String DOWN_EVT = "OtherActivityTouchConsumer.DOWN";
private final SparseArray mAnimationStates = new SparseArray<>();
private final RunningTaskInfo mRunningTask;
@@ -135,6 +139,7 @@ public class OtherActivityTouchConsumer extends ContextWrapper implements TouchC
mTouchInteractionLog.addMotionEvent(ev);
switch (ev.getActionMasked()) {
case ACTION_DOWN: {
+ RaceConditionTracker.onEvent(DOWN_EVT, ENTER);
TraceHelper.beginSection("TouchInt");
mActivePointerId = ev.getPointerId(0);
mDownPos.set(ev.getX(), ev.getY());
@@ -151,6 +156,7 @@ public class OtherActivityTouchConsumer extends ContextWrapper implements TouchC
Display display = getSystemService(WindowManager.class).getDefaultDisplay();
mDisplayRotation = display.getRotation();
WindowManagerWrapper.getInstance().getStableInsets(mStableInsets);
+ RaceConditionTracker.onEvent(DOWN_EVT, EXIT);
break;
}
case ACTION_POINTER_UP: {
diff --git a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
index 61bb75f857..b3f8a113c5 100644
--- a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
+++ b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
@@ -66,7 +66,7 @@ import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.LatencyTrackerCompat;
import com.android.systemui.shared.system.PackageManagerWrapper;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
-import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplier;
+import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat;
import com.android.systemui.shared.system.TransactionCompat;
import java.util.ArrayList;
@@ -343,8 +343,8 @@ public class OverviewCommandHelper {
clipHelper.updateTargetRect(targetRect);
clipHelper.prepareAnimation(false /* isOpening */);
- SyncRtSurfaceTransactionApplier syncTransactionApplier =
- new SyncRtSurfaceTransactionApplier(rootView);
+ SyncRtSurfaceTransactionApplierCompat syncTransactionApplier =
+ new SyncRtSurfaceTransactionApplierCompat(rootView);
ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1);
valueAnimator.setDuration(RECENTS_LAUNCH_DURATION);
valueAnimator.setInterpolator(TOUCH_RESPONSE_INTERPOLATOR);
diff --git a/quickstep/src/com/android/quickstep/TaskUtils.java b/quickstep/src/com/android/quickstep/TaskUtils.java
index 4b86a7fa88..cab3a4cdf2 100644
--- a/quickstep/src/com/android/quickstep/TaskUtils.java
+++ b/quickstep/src/com/android/quickstep/TaskUtils.java
@@ -43,7 +43,7 @@ import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskView;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
-import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplier;
+import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat;
import java.util.List;
@@ -145,8 +145,8 @@ public class TaskUtils {
*/
public static ValueAnimator getRecentsWindowAnimator(TaskView v, boolean skipViewChanges,
RemoteAnimationTargetCompat[] targets, final ClipAnimationHelper inOutHelper) {
- SyncRtSurfaceTransactionApplier syncTransactionApplier =
- new SyncRtSurfaceTransactionApplier(v);
+ SyncRtSurfaceTransactionApplierCompat syncTransactionApplier =
+ new SyncRtSurfaceTransactionApplierCompat(v);
final ValueAnimator appAnimator = ValueAnimator.ofFloat(0, 1);
appAnimator.setInterpolator(TOUCH_RESPONSE_INTERPOLATOR);
appAnimator.addUpdateListener(new MultiValueUpdateListener() {
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index b1a214d9dd..a42ee094f4 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -249,7 +249,7 @@ public class TouchInteractionService extends Service {
if (runningTaskInfo == null && !forceToLauncher) {
return TouchConsumer.NO_OP;
} else if (forceToLauncher ||
- runningTaskInfo.topActivity.equals(mOverviewCommandHelper.overviewComponent)) {
+ mOverviewCommandHelper.getActivityControlHelper().isResumed()) {
return OverviewTouchConsumer.newInstance(
mOverviewCommandHelper.getActivityControlHelper(), false, mTouchInteractionLog);
} else {
@@ -257,10 +257,10 @@ public class TouchInteractionService extends Service {
tracker = VelocityTracker.obtain();
}
return new OtherActivityTouchConsumer(this, runningTaskInfo, mRecentsModel,
- mOverviewCommandHelper.overviewIntent,
- mOverviewCommandHelper.getActivityControlHelper(), mMainThreadExecutor,
- mBackgroundThreadChoreographer, downHitTarget, mOverviewCallbacks,
- mTaskOverlayFactory, mInputConsumer, tracker, mTouchInteractionLog);
+ mOverviewCommandHelper.overviewIntent,
+ mOverviewCommandHelper.getActivityControlHelper(), mMainThreadExecutor,
+ mBackgroundThreadChoreographer, downHitTarget, mOverviewCallbacks,
+ mTaskOverlayFactory, mInputConsumer, tracker, mTouchInteractionLog);
}
}
diff --git a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java
index 78a2055bb5..6e2e3d3d7c 100644
--- a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java
+++ b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java
@@ -85,7 +85,7 @@ import com.android.systemui.shared.system.InputConsumerController;
import com.android.systemui.shared.system.LatencyTrackerCompat;
import com.android.systemui.shared.system.RecentsAnimationControllerCompat;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
-import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplier;
+import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat;
import com.android.systemui.shared.system.WindowCallbacksCompat;
import java.util.StringJoiner;
@@ -213,7 +213,7 @@ public class WindowTransformSwipeHandler {
private T mActivity;
private LayoutListener mLayoutListener;
private RecentsView mRecentsView;
- private SyncRtSurfaceTransactionApplier mSyncTransactionApplier;
+ private SyncRtSurfaceTransactionApplierCompat mSyncTransactionApplier;
private QuickScrubController mQuickScrubController;
private AnimationFactory mAnimationFactory = (t, i) -> { };
@@ -403,7 +403,9 @@ public class WindowTransformSwipeHandler {
}
mRecentsView = activity.getOverviewPanel();
- mSyncTransactionApplier = new SyncRtSurfaceTransactionApplier(mRecentsView);
+ SyncRtSurfaceTransactionApplierCompat.create(mRecentsView, (applier) -> {
+ mSyncTransactionApplier = applier;
+ });
mQuickScrubController = mRecentsView.getQuickScrubController();
mLayoutListener = mActivityControlHelper.createLayoutListener(mActivity);
diff --git a/quickstep/src/com/android/quickstep/util/ClipAnimationHelper.java b/quickstep/src/com/android/quickstep/util/ClipAnimationHelper.java
index 1e1f147c16..f6af67a30f 100644
--- a/quickstep/src/com/android/quickstep/util/ClipAnimationHelper.java
+++ b/quickstep/src/com/android/quickstep/util/ClipAnimationHelper.java
@@ -46,8 +46,8 @@ import com.android.quickstep.views.TaskThumbnailView;
import com.android.systemui.shared.recents.ISystemUiProxy;
import com.android.systemui.shared.recents.utilities.RectFEvaluator;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
-import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplier;
-import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplier.SurfaceParams;
+import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat;
+import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams;
import com.android.systemui.shared.system.TransactionCompat;
import com.android.systemui.shared.system.WindowManagerWrapper;
@@ -152,7 +152,7 @@ public class ClipAnimationHelper {
}
public RectF applyTransform(RemoteAnimationTargetSet targetSet, float progress,
- @Nullable SyncRtSurfaceTransactionApplier syncTransactionApplier) {
+ @Nullable SyncRtSurfaceTransactionApplierCompat syncTransactionApplier) {
RectF currentRect;
mTmpRectF.set(mTargetRect);
Utilities.scaleRectFAboutCenter(mTmpRectF, mTargetScale);
@@ -218,14 +218,14 @@ public class ClipAnimationHelper {
return mCurrentRectWithInsets;
}
- private void applyParams(@Nullable SyncRtSurfaceTransactionApplier syncTransactionApplier,
+ private void applyParams(@Nullable SyncRtSurfaceTransactionApplierCompat syncTransactionApplier,
SurfaceParams[] params) {
if (syncTransactionApplier != null) {
syncTransactionApplier.scheduleApply(params);
} else {
TransactionCompat t = new TransactionCompat();
for (SurfaceParams param : params) {
- SyncRtSurfaceTransactionApplier.applyParams(t, param);
+ SyncRtSurfaceTransactionApplierCompat.applyParams(t, param);
}
t.setEarlyWakeup();
t.apply();
diff --git a/quickstep/tests/src/com/android/quickstep/StartLauncherViaGestureTests.java b/quickstep/tests/src/com/android/quickstep/StartLauncherViaGestureTests.java
new file mode 100644
index 0000000000..52f3c538c6
--- /dev/null
+++ b/quickstep/tests/src/com/android/quickstep/StartLauncherViaGestureTests.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep;
+
+import static com.android.launcher3.util.RaceConditionTracker.enterEvt;
+import static com.android.launcher3.util.RaceConditionTracker.exitEvt;
+
+import android.content.Intent;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.launcher3.Launcher;
+import com.android.launcher3.util.RaceConditionReproducer;
+import com.android.quickstep.QuickStepOnOffRule.Mode;
+import com.android.quickstep.QuickStepOnOffRule.QuickstepOnOff;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@LargeTest
+@RunWith(AndroidJUnit4.class)
+public class StartLauncherViaGestureTests extends AbstractQuickStepTest {
+ @Override
+ @Before
+ public void setUp() throws Exception {
+ super.setUp();
+ // Start an activity where the gestures start.
+ startAppFast(resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR));
+ }
+
+ private void runTest(String... eventSequence) {
+ final RaceConditionReproducer eventProcessor = new RaceConditionReproducer(eventSequence);
+
+ // Destroy Launcher activity.
+ closeLauncherActivity();
+
+ // The test action.
+ eventProcessor.startIteration();
+ mLauncher.pressHome();
+ eventProcessor.finishIteration();
+ }
+
+ @Test
+ @QuickstepOnOff(mode = Mode.ON)
+ public void testPressHome() {
+ runTest(enterEvt(Launcher.ON_CREATE_EVT),
+ exitEvt(Launcher.ON_CREATE_EVT),
+ enterEvt(OtherActivityTouchConsumer.DOWN_EVT),
+ exitEvt(OtherActivityTouchConsumer.DOWN_EVT));
+
+ runTest(enterEvt(OtherActivityTouchConsumer.DOWN_EVT),
+ exitEvt(OtherActivityTouchConsumer.DOWN_EVT),
+ enterEvt(Launcher.ON_CREATE_EVT),
+ exitEvt(Launcher.ON_CREATE_EVT));
+ }
+
+ @Test
+ @QuickstepOnOff(mode = Mode.ON)
+ public void testSwipeToOverview() {
+ closeLauncherActivity();
+ mLauncher.getBackground().switchToOverview();
+ }
+}
\ No newline at end of file
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTests.java b/quickstep/tests/src/com/android/quickstep/TaplTests.java
new file mode 100644
index 0000000000..6a1123e02e
--- /dev/null
+++ b/quickstep/tests/src/com/android/quickstep/TaplTests.java
@@ -0,0 +1,462 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep;
+
+import static androidx.test.InstrumentationRegistry.getInstrumentation;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import android.content.Intent;
+import android.os.RemoteException;
+import android.util.Log;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
+import androidx.test.uiautomator.By;
+import androidx.test.uiautomator.Until;
+
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherState;
+import com.android.launcher3.tapl.AllApps;
+import com.android.launcher3.tapl.AllAppsFromOverview;
+import com.android.launcher3.tapl.AppIcon;
+import com.android.launcher3.tapl.Background;
+import com.android.launcher3.tapl.Overview;
+import com.android.launcher3.tapl.OverviewTask;
+import com.android.launcher3.tapl.TestHelpers;
+import com.android.launcher3.tapl.Widgets;
+import com.android.launcher3.tapl.Workspace;
+import com.android.launcher3.views.OptionsPopupView;
+import com.android.launcher3.widget.WidgetsFullSheet;
+import com.android.launcher3.widget.WidgetsRecyclerView;
+import com.android.quickstep.QuickStepOnOffRule.QuickstepOnOff;
+import com.android.quickstep.views.RecentsView;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TestWatcher;
+import org.junit.runner.Description;
+import org.junit.runner.RunWith;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+
+@LargeTest
+@RunWith(AndroidJUnit4.class)
+public class TaplTests extends AbstractQuickStepTest {
+ private static final String TAG = "TaplTests";
+
+ private static int sScreenshotCount = 0;
+
+ @Rule
+ public TestWatcher mFailureWatcher = new TestWatcher() {
+ private void dumpViewHierarchy() {
+ final ByteArrayOutputStream stream = new ByteArrayOutputStream();
+ try {
+ mDevice.dumpWindowHierarchy(stream);
+ stream.flush();
+ stream.close();
+ for (String line : stream.toString().split("\\r?\\n")) {
+ Log.e(TaplTests.TAG, line.trim());
+ }
+ } catch (IOException e) {
+ Log.e(TaplTests.TAG, "error dumping XML to logcat", e);
+ }
+ }
+
+ @Override
+ protected void failed(Throwable e, Description description) {
+ if (mDevice == null) return;
+ final String pathname = getInstrumentation().getTargetContext().
+ getFilesDir().getPath() + "/TaplTestScreenshot" + sScreenshotCount++ + ".png";
+ Log.e(TaplTests.TAG, "Failed test " + description.getMethodName() +
+ ", screenshot will be saved to " + pathname +
+ ", track trace is below, UI object dump is further below:\n" +
+ Log.getStackTraceString(e));
+ dumpViewHierarchy();
+ mDevice.takeScreenshot(new File(pathname));
+ }
+ };
+
+ @Before
+ public void setUp() throws Exception {
+ super.setUp();
+
+ clearLauncherData();
+
+ mDevice.pressHome();
+ waitForState("Launcher internal state didn't switch to Home", LauncherState.NORMAL);
+ waitForResumed("Launcher internal state is still Background");
+ }
+
+ private boolean isInState(LauncherState state) {
+ if (!TestHelpers.isInLauncherProcess()) return true;
+ return getFromLauncher(launcher -> launcher.getStateManager().getState() == state);
+ }
+
+ // Please don't add negative test cases for methods that fail only after a long wait.
+ private void expectFail(String message, Runnable action) {
+ boolean failed = false;
+ try {
+ action.run();
+ } catch (AssertionError e) {
+ failed = true;
+ }
+ assertTrue(message, failed);
+ }
+
+ private boolean isWorkspaceScrollable(Launcher launcher) {
+ return launcher.getWorkspace().getPageCount() > 1;
+ }
+
+ private boolean isInBackground(Launcher launcher) {
+ return !launcher.hasBeenResumed();
+ }
+
+ private void startTestApps() throws Exception {
+ startAppFast(resolveSystemApp(Intent.CATEGORY_APP_MESSAGING));
+ startAppFast(resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR));
+ startAppFast(resolveSystemApp(Intent.CATEGORY_APP_CONTACTS));
+
+ executeOnLauncher(launcher -> assertTrue(
+ "Launcher activity is the top activity; expecting another activity to be the top "
+ + "one",
+ isInBackground(launcher)));
+ }
+
+ private int getCurrentWorkspacePage(Launcher launcher) {
+ return launcher.getWorkspace().getCurrentPage();
+ }
+
+ private WidgetsRecyclerView getWidgetsView(Launcher launcher) {
+ return WidgetsFullSheet.getWidgetsView(launcher);
+ }
+
+ @Test
+ public void testDevicePressMenu() throws Exception {
+ mDevice.pressMenu();
+ mDevice.waitForIdle();
+ executeOnLauncher(
+ launcher -> assertTrue("Launcher internal state didn't switch to Showing Menu",
+ OptionsPopupView.getOptionsPopup(launcher) != null));
+ }
+
+ @Test
+ @PortraitLandscape
+ public void testPressRecentAppsLauncherAndGetOverview() throws RemoteException {
+ mDevice.pressRecentApps();
+ waitForState("Launcher internal state didn't switch to Overview", LauncherState.OVERVIEW);
+
+ assertNotNull("getOverview() returned null", mLauncher.getOverview());
+ }
+
+ private void runAllAppsTest(AllApps allApps) throws Exception {
+ assertNotNull("allApps parameter is null", allApps);
+
+ assertTrue("Launcher internal state is not All Apps", isInState(LauncherState.ALL_APPS));
+
+ // Test flinging forward and backward.
+ executeOnLauncher(launcher -> assertEquals("All Apps started in already scrolled state", 0,
+ getAllAppsScroll(launcher)));
+
+ allApps.flingForward();
+ assertTrue("Launcher internal state is not All Apps", isInState(LauncherState.ALL_APPS));
+ final Integer flingForwardY = getFromLauncher(launcher -> getAllAppsScroll(launcher));
+ executeOnLauncher(
+ launcher -> assertTrue("flingForward() didn't scroll App Apps", flingForwardY > 0));
+
+ allApps.flingBackward();
+ assertTrue("Launcher internal state is not All Apps", isInState(LauncherState.ALL_APPS));
+ final Integer flingBackwardY = getFromLauncher(launcher -> getAllAppsScroll(launcher));
+ executeOnLauncher(launcher -> assertTrue("flingBackward() didn't scroll App Apps",
+ flingBackwardY < flingForwardY));
+
+ // Test scrolling down to YouTube.
+ assertNotNull("All apps: can't fine YouTube", allApps.getAppIcon("YouTube"));
+ // Test scrolling up to Camera.
+ assertNotNull("All apps: can't fine Camera", allApps.getAppIcon("Camera"));
+ // Test failing to find a non-existing app.
+ final AllApps allAppsFinal = allApps;
+ expectFail("All apps: could find a non-existing app",
+ () -> allAppsFinal.getAppIcon("NO APP"));
+
+ assertTrue("Launcher internal state is not All Apps", isInState(LauncherState.ALL_APPS));
+ }
+
+ private int getAllAppsScroll(Launcher launcher) {
+ return launcher.getAppsView().getActiveRecyclerView().getCurrentScrollY();
+ }
+
+ @Test
+ @PortraitLandscape
+ public void testAllAppsFromHome() throws Exception {
+ // Test opening all apps
+ assertNotNull("switchToAllApps() returned null",
+ mLauncher.getWorkspace().switchToAllApps());
+
+ runAllAppsTest(mLauncher.getAllApps());
+
+ // Testing pressHome.
+ assertTrue("Launcher internal state is not All Apps", isInState(LauncherState.ALL_APPS));
+ assertNotNull("pressHome returned null", mLauncher.pressHome());
+ assertTrue("Launcher internal state is not Home", isInState(LauncherState.NORMAL));
+ assertNotNull("getHome returned null", mLauncher.getWorkspace());
+ }
+
+ @Test
+ @QuickstepOnOff
+ @PortraitLandscape
+ public void testWorkspaceSwitchToAllApps() {
+ assertNotNull("switchToAllApps() returned null",
+ mLauncher.getWorkspace().switchToAllApps());
+ assertTrue("Launcher internal state is not All Apps", isInState(LauncherState.ALL_APPS));
+ }
+
+ @Test
+ public void testAllAppsFromOverview() throws Exception {
+ // Test opening all apps from Overview.
+ assertNotNull("switchToAllApps() returned null",
+ mLauncher.getWorkspace().switchToOverview().switchToAllApps());
+
+ runAllAppsTest(mLauncher.getAllAppsFromOverview());
+ }
+
+ @Test
+ public void testWorkspace() throws Exception {
+ final Workspace workspace = mLauncher.getWorkspace();
+
+ // Test that ensureWorkspaceIsScrollable adds a page by dragging an icon there.
+ executeOnLauncher(launcher -> assertFalse("Initial workspace state is scrollable",
+ isWorkspaceScrollable(launcher)));
+ assertNull("Messages app was found on empty workspace",
+ workspace.tryGetWorkspaceAppIcon("Messages"));
+
+ workspace.ensureWorkspaceIsScrollable();
+
+ executeOnLauncher(
+ launcher -> assertEquals("Ensuring workspace scrollable didn't switch to page #1",
+ 1, getCurrentWorkspacePage(launcher)));
+ executeOnLauncher(
+ launcher -> assertTrue("ensureScrollable didn't make workspace scrollable",
+ isWorkspaceScrollable(launcher)));
+ assertNotNull("ensureScrollable didn't add Messages app",
+ workspace.tryGetWorkspaceAppIcon("Messages"));
+
+ // Test flinging workspace.
+ workspace.flingBackward();
+ assertTrue("Launcher internal state is not Home", isInState(LauncherState.NORMAL));
+ executeOnLauncher(
+ launcher -> assertEquals("Flinging back didn't switch workspace to page #0",
+ 0, getCurrentWorkspacePage(launcher)));
+
+ workspace.flingForward();
+ executeOnLauncher(
+ launcher -> assertEquals("Flinging forward didn't switch workspace to page #1",
+ 1, getCurrentWorkspacePage(launcher)));
+ assertTrue("Launcher internal state is not Home", isInState(LauncherState.NORMAL));
+
+ // Test starting a workspace app.
+ final AppIcon app = workspace.tryGetWorkspaceAppIcon("Messages");
+ assertNotNull("No Messages app in workspace", app);
+ assertNotNull("AppIcon.launch returned null",
+ app.launch(resolveSystemApp(Intent.CATEGORY_APP_MESSAGING)));
+ executeOnLauncher(launcher -> assertTrue(
+ "Launcher activity is the top activity; expecting another activity to be the top "
+ + "one",
+ isInBackground(launcher)));
+ }
+
+ @Test
+ @PortraitLandscape
+ public void testOverview() throws Exception {
+ startTestApps();
+ Overview overview = mLauncher.pressHome().switchToOverview();
+ assertTrue("Launcher internal state didn't switch to Overview",
+ isInState(LauncherState.OVERVIEW));
+ executeOnLauncher(
+ launcher -> assertTrue("Don't have at least 3 tasks", getTaskCount(launcher) >= 3));
+
+ // Test flinging forward and backward.
+ executeOnLauncher(launcher -> assertEquals("Current task in Overview is not 0",
+ 0, getCurrentOverviewPage(launcher)));
+
+ overview.flingForward();
+ assertTrue("Launcher internal state is not Overview", isInState(LauncherState.OVERVIEW));
+ final Integer currentTaskAfterFlingForward = getFromLauncher(
+ launcher -> getCurrentOverviewPage(launcher));
+ executeOnLauncher(launcher -> assertTrue("Current task in Overview is still 0",
+ currentTaskAfterFlingForward > 0));
+
+ overview.flingBackward();
+ assertTrue("Launcher internal state is not Overview", isInState(LauncherState.OVERVIEW));
+ executeOnLauncher(launcher -> assertTrue("Flinging back in Overview did nothing",
+ getCurrentOverviewPage(launcher) < currentTaskAfterFlingForward));
+
+ // Test opening a task.
+ OverviewTask task = mLauncher.pressHome().switchToOverview().getCurrentTask();
+ assertNotNull("overview.getCurrentTask() returned null (1)", task);
+ assertNotNull("OverviewTask.open returned null", task.open());
+ assertTrue("Contacts app didn't open from Overview", mDevice.wait(Until.hasObject(
+ By.pkg(resolveSystemApp(Intent.CATEGORY_APP_CONTACTS)).depth(0)),
+ LONG_WAIT_TIME_MS));
+ executeOnLauncher(launcher -> assertTrue(
+ "Launcher activity is the top activity; expecting another activity to be the top "
+ + "one",
+ isInBackground(launcher)));
+
+ // Test dismissing a task.
+ overview = mLauncher.pressHome().switchToOverview();
+ assertTrue("Launcher internal state didn't switch to Overview",
+ isInState(LauncherState.OVERVIEW));
+ final Integer numTasks = getFromLauncher(launcher -> getTaskCount(launcher));
+ task = overview.getCurrentTask();
+ assertNotNull("overview.getCurrentTask() returned null (2)", task);
+ task.dismiss();
+ executeOnLauncher(
+ launcher -> assertEquals("Dismissing a task didn't remove 1 task from Overview",
+ numTasks - 1, getTaskCount(launcher)));
+
+ if (!TestHelpers.isInLauncherProcess() ||
+ getFromLauncher(launcher -> !launcher.getDeviceProfile().isLandscape)) {
+ // Test switching to all apps and back.
+ final AllAppsFromOverview allApps = overview.switchToAllApps();
+ assertNotNull("overview.switchToAllApps() returned null (1)", allApps);
+ assertTrue("Launcher internal state is not All Apps (1)",
+ isInState(LauncherState.ALL_APPS));
+
+ overview = allApps.switchBackToOverview();
+ assertNotNull("allApps.switchBackToOverview() returned null", overview);
+ assertTrue("Launcher internal state didn't switch to Overview",
+ isInState(LauncherState.OVERVIEW));
+
+ // Test UIDevice.pressBack()
+ overview.switchToAllApps();
+ assertNotNull("overview.switchToAllApps() returned null (2)", allApps);
+ assertTrue("Launcher internal state is not All Apps (2)",
+ isInState(LauncherState.ALL_APPS));
+ mDevice.pressBack();
+ mLauncher.getOverview();
+ }
+
+ // Test UIDevice.pressHome, once we are in AllApps.
+ mDevice.pressHome();
+ waitForState("Launcher internal state didn't switch to Home", LauncherState.NORMAL);
+ }
+
+ private int getCurrentOverviewPage(Launcher launcher) {
+ return launcher.getOverviewPanel().getCurrentPage();
+ }
+
+ private int getTaskCount(Launcher launcher) {
+ return launcher.getOverviewPanel().getTaskViewCount();
+ }
+
+ private void runIconLaunchFromAllAppsTest(AllApps allApps) throws Exception {
+ final AppIcon app = allApps.getAppIcon("Calculator");
+ assertNotNull("AppIcon.launch returned null", app.launch(
+ resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR)));
+ executeOnLauncher(launcher -> assertTrue(
+ "Launcher activity is the top activity; expecting another activity to be the top "
+ + "one",
+ isInBackground(launcher)));
+ }
+
+ @Test
+ @PortraitLandscape
+ public void testAppIconLaunchFromAllAppsFromHome() throws Exception {
+ final AllApps allApps = mLauncher.getWorkspace().switchToAllApps();
+ assertTrue("Launcher internal state is not All Apps", isInState(LauncherState.ALL_APPS));
+
+ runIconLaunchFromAllAppsTest(allApps);
+ }
+
+ @Test
+ public void testAppIconLaunchFromAllAppsFromOverview() throws Exception {
+ final AllApps allApps =
+ mLauncher.getWorkspace().switchToOverview().switchToAllApps();
+ assertTrue("Launcher internal state is not All Apps", isInState(LauncherState.ALL_APPS));
+
+ runIconLaunchFromAllAppsTest(allApps);
+ }
+
+ @Test
+ @PortraitLandscape
+ public void testWidgets() throws Exception {
+ // Test opening widgets.
+ executeOnLauncher(launcher ->
+ assertTrue("Widgets is initially opened", getWidgetsView(launcher) == null));
+ Widgets widgets = mLauncher.getWorkspace().openAllWidgets();
+ assertNotNull("openAllWidgets() returned null", widgets);
+ widgets = mLauncher.getAllWidgets();
+ assertNotNull("getAllWidgets() returned null", widgets);
+ executeOnLauncher(launcher ->
+ assertTrue("Widgets is not shown", getWidgetsView(launcher).isShown()));
+ executeOnLauncher(launcher -> assertEquals("Widgets is scrolled upon opening",
+ 0, getWidgetsScroll(launcher)));
+
+ // Test flinging widgets.
+ widgets.flingForward();
+ Integer flingForwardY = getFromLauncher(launcher -> getWidgetsScroll(launcher));
+ executeOnLauncher(launcher -> assertTrue("Flinging forward didn't scroll widgets",
+ flingForwardY > 0));
+
+ widgets.flingBackward();
+ executeOnLauncher(launcher -> assertTrue("Flinging backward didn't scroll widgets",
+ getWidgetsScroll(launcher) < flingForwardY));
+
+ mDevice.pressHome();
+ waitForLauncherCondition("Widgets were not closed",
+ launcher -> getWidgetsView(launcher) == null);
+ }
+
+ private int getWidgetsScroll(Launcher launcher) {
+ return getWidgetsView(launcher).getCurrentScrollY();
+ }
+
+ @Test
+ @QuickstepOnOff
+ @PortraitLandscape
+ public void testSwitchToOverview() throws Exception {
+ assertNotNull("Workspace.switchToOverview() returned null",
+ mLauncher.pressHome().switchToOverview());
+ assertTrue("Launcher internal state didn't switch to Overview",
+ isInState(LauncherState.OVERVIEW));
+ }
+
+ @Test
+ @QuickstepOnOff
+ @PortraitLandscape
+ public void testBackground() throws Exception {
+ startAppFast(resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR));
+ final Background background = mLauncher.getBackground();
+ assertNotNull("Launcher.getBackground() returned null", background);
+ executeOnLauncher(launcher -> assertTrue(
+ "Launcher activity is the top activity; expecting another activity to be the top "
+ + "one",
+ isInBackground(launcher)));
+
+ assertNotNull("Background.switchToOverview() returned null", background.switchToOverview());
+ assertTrue("Launcher internal state didn't switch to Overview",
+ isInState(LauncherState.OVERVIEW));
+ }
+}
diff --git a/res/raw/downgrade_schema.json b/res/raw/downgrade_schema.json
index 3c1b64f92a..8f1780e5f7 100644
--- a/res/raw/downgrade_schema.json
+++ b/res/raw/downgrade_schema.json
@@ -2,8 +2,12 @@
// Note: Comments are not supported in JSON schema, but android parser is lenient.
// Maximum DB version supported by this schema
- "version" : 27,
+ "version" : 28,
+ "downgrade_to_27" : [
+ "CREATE TABLE workspaceScreens (_id INTEGER PRIMARY KEY,screenRank INTEGER,modified INTEGER NOT NULL DEFAULT 0)",
+ "insert into workspaceScreens (_id, screenRank) select screen as _id, screen as screenRank from favorites where container = -100 group by screen order by screen"
+ ],
// Downgrade from 27 to 26. Empty array indicates, the DB is compatible
"downgrade_to_26" : [],
"downgrade_to_25" : [],
diff --git a/res/values-af/strings.xml b/res/values-af/strings.xml
index b93c3701eb..3f505462ee 100644
--- a/res/values-af/strings.xml
+++ b/res/values-af/strings.xml
@@ -39,8 +39,7 @@
"Laai tans programme …"
"Kon geen programme kry wat by \"%1$s\" pas nie"
"Soek meer programme"
-
-
+ "Program"
"Kennisgewings"
"Raak en hou om \'n kortpad op te tel."
"Dubbeltik en hou om \'n kortpad op te tel of gebruik gepasmaakte handelinge."
@@ -66,7 +65,10 @@
"Dit is \'n stelselprogram en kan nie gedeïnstalleer word nie."
"Naamlose vouer"
"Het %1$s gedeaktiveer"
-
+
+ - %1$s, het %2$d kennisgewings
+ - %1$s, het %2$d kennisgewing
+
"Bladsy %1$d van %2$d"
"Tuisskerm %1$d van %2$d"
"Nuwe tuisskermbladsy"
@@ -82,17 +84,13 @@
"Gedeaktiveer deur jou administrateur"
"Laat toe dat tuisskerm gedraai word"
"Wanneer foon gedraai word"
-
-
-
-
-
-
+ "Kennisgewingkolle"
+ "Aan"
+ "Af"
"Kennisgewingtoegang word benodig"
"Skakel programkennisgewings vir %1$s aan om kennisgewingkolle te sien"
"Verander instellings"
-
-
+ "Wys kennisgewingkolle"
"Voeg ikoon by tuisskerm"
"Vir nuwe programme"
"Verander ikoon se vorm"
diff --git a/res/values-am/strings.xml b/res/values-am/strings.xml
index d65fa673d7..9f8ee87ca5 100644
--- a/res/values-am/strings.xml
+++ b/res/values-am/strings.xml
@@ -39,8 +39,7 @@
"መተግበሪያዎችን በመጫን ላይ…"
"ከ«%1$s» ጋር የሚዛመዱ ምንም መተግበሪያዎች አልተገኙም"
"ተጨማሪ መተግበሪያዎች ይፈልጉ"
-
-
+ "መተግበሪያ"
"ማሳወቂያዎች"
"አንድ አቋራጭ ለመውሰድ ነክተው ይያዙ።"
"አንድ አቋራጭ ለመውሰድ ወይም ብጁ እርምጃዎችን ለመጠቀም ሁለቴ መታ አድርገው ይያዙ።"
@@ -66,7 +65,10 @@
"ይህ የስርዓት መተግበሪያ ነው እና ማራገፍ አይቻልም።"
"ስም-አልባ አቃፊ"
"%1$s ተሰናክሏል"
-
+
+ - %1$s፣ %2$d ማሳወቂያ አለው
+ - %1$s፣ %2$d ማሳወቂያ አለው
+
"ገጽ %1$d ከ%2$d"
"መነሻ ማያ ገጽ %1$d ከ%2$d"
"አዲስ የመነሻ ማያ ገጽ"
@@ -82,17 +84,13 @@
"በእርስዎ አስተዳዳሪ የተሰናከለ"
"የመነሻ ማያ ገጽ ማሽከርከርን ይፍቀዱ"
"ስልኩ ሲዞር"
-
-
-
-
-
-
+ "የማሳወቂያ ነጥቦች"
+ "አብራ"
+ "ጠፍቷል"
"የማሳወቂያ መዳረሻ ያስፈልጋል"
"የማሳወቂያ ነጥቦችን ለማሳየት የመተግብሪያ ማሳወቂያዎችን ለ%1$s ያብሩ"
"ቅንብሮችን ቀይር"
-
-
+ "የማሳወቂያ ነጥቦችን አሳይ"
"አዶ ወደ የመነሻ ማያ ገጽ አክል"
"ለአዲስ መተግበሪያዎች"
"የአዶ ቅርፅ ለውጥ"
diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml
index 988f9b9e29..97e9784d2f 100644
--- a/res/values-ar/strings.xml
+++ b/res/values-ar/strings.xml
@@ -39,8 +39,7 @@
"جارٍ تحميل التطبيقات…"
"لم يتم العثور على أي تطبيقات تتطابق مع \"%1$s\""
"البحث عن مزيد من التطبيقات"
-
-
+ "تطبيق"
"الإشعارات"
"انقر مع الاستمرار لاختيار اختصار."
"يمكنك النقر مرّتين مع الاستمرار لاختيار اختصار أو استخدام الإجراءات المخصصة."
@@ -66,7 +65,14 @@
"هذا تطبيق نظام وتتعذر إزالته."
"مجلد بدون اسم"
"تم إيقاف %1$s"
-
+
+ - يتضمن تطبيق %1$s %2$d إشعار.
+ - يتضمن تطبيق %1$s إشعارين (%2$d).
+ - يتضمن تطبيق %1$s %2$d إشعارات.
+ - يتضمن تطبيق %1$s %2$d إشعارًا.
+ - يتضمن تطبيق %1$s %2$d إشعار.
+ - يتضمن تطبيق %1$s إشعارًا واحدًا (%2$d).
+
"الصفحة %1$d من %2$d"
"الشاشة الرئيسية %1$d من %2$d"
"صفحة الشاشة الرئيسية الجديدة"
@@ -82,17 +88,13 @@
"أوقف المشرف هذه الميزة"
"السماح بتدوير الشاشة الرئيسية"
"عند تدوير الهاتف"
-
-
-
-
-
-
+ "نقاط الإشعارات"
+ "مفعّل"
+ "غير مفعّل"
"يلزم تفعيل الوصول إلى الإشعارات"
"لعرض نقاط الإشعارات، يجب تشغيل إشعارات التطبيق في %1$s"
"تغيير الإعدادات"
-
-
+ "عرض نقاط الإشعارات"
"إضافة رمز إلى الشاشة الرئيسية"
"للتطبيقات الجديدة"
"تغيير شكل الرمز"
diff --git a/res/values-as/strings.xml b/res/values-as/strings.xml
index 149a19d639..e4293cfe42 100644
--- a/res/values-as/strings.xml
+++ b/res/values-as/strings.xml
@@ -39,8 +39,7 @@
"এপসমূহ ল’ড কৰি থকা হৈছে…"
"\"%1$s\"ৰ সৈতে মিলা কোনো এপ্ বিচাৰি পোৱা নগ\'ল"
"আৰু অধিক এপবোৰ সন্ধান কৰক"
-
-
+ "এপ্"
"জাননীসমূহ"
"কোনো শ্বৰ্টকাট বাছনি কৰিবলৈ স্পৰ্শ কৰি হেঁচি ধৰক।"
"কোনো শ্বৰ্টকাট বাছনি কৰিবলৈ দুবাৰ টিপি হেঁচি ধৰক, বা নিজৰ উপযোগিতা অনুসৰি সৃষ্টি কৰা কাৰ্যসমূহ ব্যৱহাৰ কৰক।"
@@ -66,7 +65,10 @@
"এইটো এটা ছিষ্টেম এপ আৰু ইয়াক আনইনষ্টল কৰিব নোৱৰি"
"নামবিহীন ফ\'ল্ডাৰ"
"%1$s অক্ষম কৰা হ\'ল"
-
+
+ - %1$sৰ %2$dটা জাননী আছে
+ - %1$sৰ %2$dটা জাননী আছে
+
"%2$dৰ %1$d পৃষ্ঠা"
"গৃহ স্ক্ৰীণ %2$dৰ %1$d"
"গৃহ স্ক্ৰীণৰ নতুন পৃষ্ঠা"
@@ -82,17 +84,13 @@
"আপোনাৰ প্ৰশাসকে অক্ষম কৰি ৰাখিছে"
"গৃহ স্ক্ৰীণ ঘূৰোৱাৰ অনুমতি দিয়ক"
"ফ\'নটো যেতিয়া ঘূৰোৱা হয়"
-
-
-
-
-
-
+ "জাননী বিন্দু"
+ "অন আছে"
+ "অফ আছে"
"জাননী চাবলৈ অনুমতিৰ প্ৰয়োজন"
"জাননী সম্পৰ্কীয় বিন্দুবোৰ দেখুৱাবলৈ %1$sৰ বাবে এপৰ জাননীসমূহ অন কৰক"
"ছেটিংসমূহ সলনি কৰক"
-
-
+ "জাননী বিন্দু দেখুৱাওক"
"গৃহ স্ক্ৰীণত আইকনটো যোগ কৰক"
"নতুন এপসমূহৰ বাবে"
"আইকনৰ আকৃতি সলনি কৰক"
diff --git a/res/values-az/strings.xml b/res/values-az/strings.xml
index 2a8f046953..5381114d6c 100644
--- a/res/values-az/strings.xml
+++ b/res/values-az/strings.xml
@@ -39,8 +39,7 @@
"Tətbiqlər yüklənir…"
"%1$s sorğusuna uyğun tətbiq tapılmadı"
"Daha çox tətbiq üçün axtarış edin"
-
-
+ "Tətbiq"
"Bildirişlər"
"Qısayolu seçmək üçün basıb saxlayın."
"Qısayolu seçmək üçün iki dəfə basıb saxlayın və ya fərdi əməliyyatlardan istifadə edin."
@@ -66,7 +65,10 @@
"Bu sistem tətbiqi olduğu üçün sistemdən silinə bilməz."
"Adsız Qovluq"
"%1$s deaktiv edildi"
-
+
+ - %1$s tətbiqində %2$d bildiriş var
+ - %1$s tətbiqində %2$d bildiriş var
+
"Səhifə %1$d of %2$d"
"Əsas Səhifə ekranı %1$d of %2$d"
"Yeni əsas ekran səhifəsi"
@@ -82,17 +84,13 @@
"Admininiz tərəfindən deaktiv edilib"
"Əsas ekranın firlanmağına icazə verin"
"Telefon çevrilən zaman"
-
-
-
-
-
-
+ "Bildiriş nöqtələri"
+ "Aktiv"
+ "Deaktiv"
"Bildiriş girişi tələb edilir"
"Bildiriş Nöqtələrini göstərmək üçün %1$s bildirişlərini aktiv edin"
"Ayarları dəyişin"
-
-
+ "Bildiriş nöqtələrini göstərin"
"Əsas ekrana ikona əlavə edin"
"Yeni tətbiqlər üçün"
"İkona formasını dəyişin"
diff --git a/res/values-b+sr+Latn/strings.xml b/res/values-b+sr+Latn/strings.xml
index c89330e773..568a0fbc20 100644
--- a/res/values-b+sr+Latn/strings.xml
+++ b/res/values-b+sr+Latn/strings.xml
@@ -39,8 +39,7 @@
"Aplikacije se učitavaju…"
"Nije pronađena nijedna aplikacija za „%1$s“"
"Pretraži još aplikacija"
-
-
+ "Aplikacija"
"Obaveštenja"
"Dodirnite i zadržite da biste izabrali prečicu."
"Dvaput dodirnite i zadržite da biste izabrali prečicu ili koristite prilagođene radnje."
@@ -66,7 +65,11 @@
"Ovo je sistemska aplikacija i ne može da se deinstalira."
"Neimenovani direktorijum"
"Aplikacija %1$s je onemogućena"
-
+
+ - %1$s, ima %2$d obaveštenje
+ - %1$s, ima %2$d obaveštenja
+ - %1$s, ima %2$d obaveštenja
+
"%1$d. stranica od %2$d"
"%1$d. početni ekran od %2$d"
"Nova stranica početnog ekrana"
@@ -82,17 +85,13 @@
"Administrator je onemogućio"
"Dozvoli rotaciju početnog ekrana"
"Kada se telefon rotira"
-
-
-
-
-
-
+ "Tačke za obaveštenja"
+ "Uključeno"
+ "Isključeno"
"Potreban je pristup za obaveštenja"
"Da biste prikazali tačke za obaveštenja, uključite obaveštenja za aplikaciju %1$s"
"Promenite podešavanja"
-
-
+ "Prikazuj tačke za obaveštenja"
"Dodaj ikonu na početni ekran"
"Za nove aplikacije"
"Promenite oblik ikona"
diff --git a/res/values-be/strings.xml b/res/values-be/strings.xml
index 39db29ad37..2f5fd30054 100644
--- a/res/values-be/strings.xml
+++ b/res/values-be/strings.xml
@@ -39,8 +39,7 @@
"Праграмы загружаюцца…"
"Праграм, якія адпавядаюць запыту \"%1$s\", не знойдзена"
"Шукаць іншыя праграмы"
-
-
+ "Праграма"
"Апавяшчэнні"
"Дакраніцеся і ўтрымлiвайце ярлык, каб дадаць яго."
"Дакраніцеся двойчы і ўтрымлівайце, каб выбраць ярлык або выкарыстоўваць спецыяльныя дзеянні."
@@ -66,7 +65,12 @@
"Гэта сістэмная праграма, яе нельга выдаліць."
"Папка без назвы"
"%1$s адключана"
-
+
+ - %1$s, мае %2$d апавяшчэнне
+ - %1$s, мае %2$d апавяшчэнні
+ - %1$s, мае %2$d апавяшчэнняў
+ - %1$s, мае %2$d апавяшчэння
+
"Старонка %1$d з %2$d"
"Галоўны экран %1$d з %2$d"
"Новая старонка галоўнага экрана"
@@ -82,17 +86,13 @@
"Адключаная адміністратарам"
"Дазволіць паварот галоўнага экрана"
"Пры павароце тэлефона"
-
-
-
-
-
-
+ "Значкі апавяшчэнняў"
+ "Укл."
+ "Выкл."
"Патрабуецца доступ да апавяшчэнняў"
"Каб паказваліся значкі апавяшчэнняў, уключыце апавяшчэнні праграм для %1$s"
"Змяніць налады"
-
-
+ "Паказваць значкі апавяшчэнняў"
"Дадаць значок на Галоўны экран"
"Для новых праграм"
"Змяніць форму значка"
diff --git a/res/values-bg/strings.xml b/res/values-bg/strings.xml
index 9083f4ce0d..286a6e886a 100644
--- a/res/values-bg/strings.xml
+++ b/res/values-bg/strings.xml
@@ -39,8 +39,7 @@
"Приложенията се зареждат…"
"Няма намерени приложения, съответстващи на „%1$s“"
"Търсене на още приложения"
-
-
+ "Приложение"
"Известия"
"Докоснете и задръжте за избор на пряк път."
"Докоснете двукратно и задръжте за избор на пряк път или използвайте персонализирани действия."
@@ -66,7 +65,10 @@
"Това е системно приложение и не може да се деинсталира."
"Папка без име"
"Деактивирахте %1$s"
-
+
+ - %1$s – има %2$d известия
+ - %1$s – има %2$d известие
+
"Страница %1$d от %2$d"
"Начален екран %1$d от %2$d"
"Нова страница на началния екран"
@@ -82,17 +84,13 @@
"Деактивирано от администратора ви"
"Разрешаване на завъртането на началния екран"
"При завъртане на телефона"
-
-
-
-
-
-
+ "Точки за известия"
+ "Вкл."
+ "Изкл."
"Необходим е достъп до известията"
"За да се показват точки за известия, включете известията за приложението %1$s"
"Промяна на настройките"
-
-
+ "Показване на точките за известия"
"Добавяне на икона към началния екран"
"За нови приложения"
"Промяна на формата на иконите"
diff --git a/res/values-bn/strings.xml b/res/values-bn/strings.xml
index c5adb7b1c2..6356f149d7 100644
--- a/res/values-bn/strings.xml
+++ b/res/values-bn/strings.xml
@@ -39,8 +39,7 @@
"অ্যাপ লোড হচ্ছে…"
"\"%1$s\" এর সাথে মেলে এমন কোনো অ্যাপ পাওয়া যায়নি"
"আরও অ্যাপ্লিকেশানের জন্য খুঁজুন"
-
-
+ "অ্যাপ"
"বিজ্ঞপ্তি"
"কোনও শর্টকাট বেছে নিতে টাচ করে ধরে থাকুন।"
"কোনও শর্টকাট বেছে নিতে ডবল ট্যাপ করে ধরে থাকুন অথবা কাস্টম অ্যাকশন ব্যবহার করুন।"
@@ -66,7 +65,10 @@
"এটি একটি সিস্টেম অ্যাপ্লিকেশান এবং আনইনস্টল করা যাবে না৷"
"নামবিহীন ফোল্ডার"
"%1$s অক্ষম করা হয়েছে"
-
+
+ - %1$s, %2$dটি বিজ্ঞপ্তি আছে
+ - %1$s, %2$dটি বিজ্ঞপ্তি আছে
+
"%2$dটির মধ্যে %1$dটি পৃষ্ঠা"
"%2$dটির %1$d নম্বর হোম স্ক্রিন"
"নতুন হোম স্ক্রীনের পৃষ্ঠা"
@@ -82,17 +84,13 @@
"আপনার প্রশাসক দ্বারা অক্ষম করা হয়েছে"
"হোমস্ক্রীন ঘোরানোর অনুমতি দিন"
"যখন ফোনটি ঘোরানো হয়"
-
-
-
-
-
-
+ "বিজ্ঞপ্তি ডট"
+ "চালু"
+ "বন্ধ"
"বিজ্ঞপ্তিতে অ্যাক্সেস প্রয়োজন"
"বিজ্ঞপ্তির ডটগুলি দেখানোর জন্য, %1$s এর অ্যাপ বিজ্ঞপ্তি চালু করুন"
"সেটিংস পরিবর্তন করুন"
-
-
+ "বিজ্ঞপ্তির ডট দেখুন"
"হোম স্ক্রিনে আইকন যোগ করুন"
"নতুন অ্যাপ্লিকেশানগুলির জন্যে"
"আইকনের আকৃতি পরিবর্তন করুন"
diff --git a/res/values-bs/strings.xml b/res/values-bs/strings.xml
index 74624cad7f..e98e1cde3a 100644
--- a/res/values-bs/strings.xml
+++ b/res/values-bs/strings.xml
@@ -39,8 +39,7 @@
"Aplikacije se učitavaju…"
"Nije pronađena nijedna aplikacija za upit \"%1$s\""
"Pretraži više aplikacija"
-
-
+ "Aplikacija"
"Obavještenja"
"Dodirnite i držite da uzmete prečicu."
"Dodirnite dvaput i držite da uzmete prečicu ili koristite prilagođene akcije."
@@ -66,7 +65,11 @@
"Ovo je sistemska aplikacija i ne može se deinstalirati."
"Neimenovani folder"
"Aplikacija %1$s je onemogućena"
-
+
+ - Aplikacija %1$s ima%2$d obavještenje
+ - Aplikacija %1$s ima%2$d obavještenja
+ - Aplikacija %1$s ima%2$d obavještenja
+
"Strana %1$d od %2$d"
"Početni ekran %1$d od %2$d"
"Nova stranica početnog ekrana"
@@ -82,17 +85,13 @@
"Onemogućio vaš administrator"
"Dozvoli rotiranje početnog ekrana"
"Kada se telefon zarotira"
-
-
-
-
-
-
+ "Tačke za obavještenja"
+ "Uključeno"
+ "Isključeno"
"Potreban je pristup obavještenjima"
"Za prikaz tačaka obavještenja, uključite obavještenja za aplikacije za aplikaciju %1$s"
"Promijeni postavke"
-
-
+ "Prikaži tačke za obavještenja"
"Dodaj ikonu na početni ekran"
"Za nove aplikacije"
"Promjena oblika ikona"
diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml
index b34dcb67c2..52cd6a3bbb 100644
--- a/res/values-ca/strings.xml
+++ b/res/values-ca/strings.xml
@@ -39,8 +39,7 @@
"S\'estan carregant les aplicacions…"
"No s\'ha trobat cap aplicació que coincideixi amb \"%1$s\""
"Cerca més aplicacions"
-
-
+ "Aplicació"
"Notificacions"
"Mantén premuda una drecera per seleccionar-la."
"Fes doble toc i mantén premut per seleccionar una drecera o per utilitzar accions personalitzades."
@@ -66,7 +65,10 @@
"Aquesta aplicació és una aplicació del sistema i no es pot desinstal·lar."
"Carpeta sense nom"
"S\'ha desactivat %1$s"
-
+
+ - %1$s té %2$d notificacions
+ - %1$s té %2$d notificació
+
"Pàgina %1$d de %2$d"
"Pantalla d\'inici %1$d de %2$d"
"Pàgina de la pantalla d\'inici nova"
@@ -82,17 +84,13 @@
"Desactivada per l\'administrador"
"Permet la rotació de la pantalla d\'inici"
"En girar el telèfon"
-
-
-
-
-
-
+ "Punts de notificació"
+ "Activats"
+ "Desactivats"
"Cal que tingui accés a les notificacions"
"Per veure els punts de notificació, activa les notificacions de l\'aplicació %1$s"
"Canvia la configuració"
-
-
+ "Mostra els punts de notificació"
"Afegeix la icona a la pantalla d\'inici"
"Per a les aplicacions noves"
"Canvia la forma de les icones"
diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml
index 187b60b7f6..59dabbc403 100644
--- a/res/values-cs/strings.xml
+++ b/res/values-cs/strings.xml
@@ -39,8 +39,7 @@
"Načítání aplikací…"
"Dotazu „%1$s“ neodpovídají žádné aplikace"
"Vyhledat další aplikace"
-
-
+ "Aplikace"
"Oznámení"
"Zkratku vyberete podržením."
"Dvojitým klepnutím a podržením vyberte zkratku, případně použijte vlastní akce."
@@ -66,7 +65,12 @@
"Toto je systémová aplikace a nelze ji odinstalovat."
"Složka bez názvu"
"Aplikace %1$s je zakázána"
-
+
+ - Aplikace %1$s má %2$d oznámení
+ - Aplikace %1$s má %2$d oznámení
+ - Aplikace %1$s má %2$d oznámení
+ - Aplikace %1$s má %2$d oznámení
+
"Strana %1$d z %2$d"
"Plocha %1$d z %2$d"
"Nová stránka plochy"
@@ -82,17 +86,13 @@
"Zakázáno administrátorem"
"Povolit otáčení plochy"
"Při otočení telefonu"
-
-
-
-
-
-
+ "Puntíky s oznámením"
+ "Zapnuto"
+ "Vypnuto"
"Je třeba udělit přístup k oznámením"
"Chcete-li zobrazovat puntíky s oznámením, zapněte oznámení z aplikace %1$s"
"Změnit nastavení"
-
-
+ "Zobrazovat puntíky s oznámením"
"Přidat ikonu na plochu"
"Pro nové aplikace"
"Změnit tvar ikony"
diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml
index 745b534736..19ffe36673 100644
--- a/res/values-da/strings.xml
+++ b/res/values-da/strings.xml
@@ -39,8 +39,7 @@
"Indlæser apps…"
"Der blev ikke fundet nogen apps, som matcher \"%1$s\""
"Søg efter flere apps"
-
-
+ "App"
"Underretninger"
"Hold en genvej nede for at samle den op."
"Tryk to gange, og hold en genvej nede for at samle den op eller bruge tilpassede handlinger."
@@ -66,7 +65,10 @@
"Dette er en systemapp, som ikke kan afinstalleres."
"Unavngiven mappe"
"%1$s er deaktiveret"
-
+
+ - %1$s, har %2$d underretning
+ - %1$s, har %2$d underretninger
+
"Side %1$d ud af %2$d"
"Startskærm %1$d ud af %2$d"
"Ny startskærm"
@@ -82,17 +84,13 @@
"Deaktiveret af din administrator"
"Tillad rotation af startskærmen"
"Når telefonen roteres"
-
-
-
-
-
-
+ "Underretningscirkler"
+ "Til"
+ "Fra"
"Kræver adgang til underretninger"
"Hvis du vil se underretningscirkler, skal du aktivere appunderretninger for %1$s"
"Skift indstillinger"
-
-
+ "Vis underretningscirkler"
"Føj ikon til startskærmen"
"For nye apps"
"Skift ikonform"
diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml
index 33016318fb..4d4c1daf23 100644
--- a/res/values-de/strings.xml
+++ b/res/values-de/strings.xml
@@ -39,8 +39,7 @@
"Apps werden geladen…"
"Keine Apps für \"%1$s\" gefunden"
"Weitere Apps suchen"
-
-
+ "App"
"Benachrichtigungen"
"Tippen und halten, um eine Verknüpfung auszuwählen."
"Doppeltippen und halten, um eine Verknüpfung auszuwählen oder benutzerdefinierte Aktionen zu nutzen."
@@ -66,7 +65,10 @@
"Dies ist eine Systemanwendung, die nicht deinstalliert werden kann."
"Unbenannter Ordner"
"%1$s deaktiviert"
-
+
+ - %1$s, hat %2$d Benachrichtigungen
+ - %1$s, hat %2$d Benachrichtigung
+
"Seite %1$d von %2$d"
"Startbildschirm %1$d von %2$d"
"Neue Startbildschirmseite"
@@ -82,17 +84,13 @@
"Von deinem Administrator deaktiviert"
"Drehung des Startbildschirms zulassen"
"Bei Drehung des Smartphones"
-
-
-
-
-
-
+ "App-Benachrichtigungspunkte"
+ "An"
+ "Aus"
"Benachrichtigungszugriff erforderlich"
"Um dir Benachrichtigungspunkte anzeigen zu lassen, aktiviere die Benachrichtigungen für die App \"%1$s\""
"Einstellungen ändern"
-
-
+ "App-Benachrichtigungspunkte anzeigen"
"Symbol zu Startbildschirm hinzufügen"
"Für neue Apps"
"Form des Symbols ändern"
diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml
index 690da09e1d..35aba42a37 100644
--- a/res/values-el/strings.xml
+++ b/res/values-el/strings.xml
@@ -39,8 +39,7 @@
"Φόρτωση εφαρμογών…"
"Δεν βρέθηκαν εφαρμογές αντιστοίχισης για \"%1$s\""
"Αναζήτηση περισσότερων εφαρμογών"
-
-
+ "Εφαρμογή"
"Ειδοποιήσεις"
"Αγγίξτε παρατεταμένα για επιλογή συντόμευσης."
"Πατήσετε δύο φορές παρατεταμένα για επιλογή συντόμευσης ή χρήση προσαρμοσμένων ενεργειών."
@@ -66,7 +65,10 @@
"Αυτή είναι μια εφαρμογή συστήματος και δεν είναι δυνατή η κατάργηση της εγκατάστασής της."
"Φάκελος χωρίς όνομα"
"Η εφαρμογή %1$s είναι απενεργοποιημένη"
-
+
+ - Η εφαρμογή %1$s, έχει %2$d ειδοποιήσεις
+ - Η εφαρμογή %1$s, έχει %2$d ειδοποίηση
+
"Σελίδα %1$d από %2$d"
"Αρχική οθόνη %1$d από %2$d"
"Νέα σελίδα αρχικής οθόνης"
@@ -82,17 +84,13 @@
"Απενεργοποιήθηκε από τον διαχειριστή σας"
"Να επιτρέπεται η περιστροφή της αρχικής οθόνης"
"Όταν το τηλέφωνο περιστρέφεται"
-
-
-
-
-
-
+ "Κουκκίδες ειδοποίησης"
+ "Ενεργοποίηση"
+ "Απενεργοποίηση"
"Απαιτείται πρόσβαση στις ειδοποιήσεις"
"Για να εμφανιστούν οι Κουκκίδες ειδοποίησης, ενεργοποιήστε τις κουκκίδες εφαρμογής για την εφαρμογή %1$s"
"Αλλαγή ρυθμίσεων"
-
-
+ "Εμφάνιση κουκκίδων ειδοποιήσεων"
"Προσθήκη εικονιδίου στην Αρχική οθόνη"
"Για νέες εφαρμογές"
"Αλλαγή σχήματος εικονιδίου"
diff --git a/res/values-en-rAU/strings.xml b/res/values-en-rAU/strings.xml
index 7360892f9c..a56fbefa46 100644
--- a/res/values-en-rAU/strings.xml
+++ b/res/values-en-rAU/strings.xml
@@ -39,8 +39,7 @@
"Loading apps…"
"No apps found matching \'%1$s\'"
"Search for more apps"
-
-
+ "App"
"Notifications"
"Touch & hold to pick up a shortcut."
"Double-tap & hold to pick up a shortcut or use custom actions."
@@ -66,7 +65,10 @@
"This is a system app and can\'t be uninstalled."
"Unnamed Folder"
"Disabled %1$s"
-
+
+ - %1$s, has %2$d notifications
+ - %1$s, has %2$d notification
+
"Page %1$d of %2$d"
"Home screen %1$d of %2$d"
"New home screen page"
@@ -82,17 +84,13 @@
"Disabled by your admin"
"Allow Homescreen rotation"
"When phone is rotated"
-
-
-
-
-
-
+ "Notification dots"
+ "On"
+ "Off"
"Notification access needed"
"To show Notification Dots, turn on app notifications for %1$s"
"Change settings"
-
-
+ "Show notification dots"
"Add icon to Home screen"
"For new apps"
"Change icon shape"
diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml
index 7360892f9c..a56fbefa46 100644
--- a/res/values-en-rGB/strings.xml
+++ b/res/values-en-rGB/strings.xml
@@ -39,8 +39,7 @@
"Loading apps…"
"No apps found matching \'%1$s\'"
"Search for more apps"
-
-
+ "App"
"Notifications"
"Touch & hold to pick up a shortcut."
"Double-tap & hold to pick up a shortcut or use custom actions."
@@ -66,7 +65,10 @@
"This is a system app and can\'t be uninstalled."
"Unnamed Folder"
"Disabled %1$s"
-
+
+ - %1$s, has %2$d notifications
+ - %1$s, has %2$d notification
+
"Page %1$d of %2$d"
"Home screen %1$d of %2$d"
"New home screen page"
@@ -82,17 +84,13 @@
"Disabled by your admin"
"Allow Homescreen rotation"
"When phone is rotated"
-
-
-
-
-
-
+ "Notification dots"
+ "On"
+ "Off"
"Notification access needed"
"To show Notification Dots, turn on app notifications for %1$s"
"Change settings"
-
-
+ "Show notification dots"
"Add icon to Home screen"
"For new apps"
"Change icon shape"
diff --git a/res/values-en-rIN/strings.xml b/res/values-en-rIN/strings.xml
index 7360892f9c..a56fbefa46 100644
--- a/res/values-en-rIN/strings.xml
+++ b/res/values-en-rIN/strings.xml
@@ -39,8 +39,7 @@
"Loading apps…"
"No apps found matching \'%1$s\'"
"Search for more apps"
-
-
+ "App"
"Notifications"
"Touch & hold to pick up a shortcut."
"Double-tap & hold to pick up a shortcut or use custom actions."
@@ -66,7 +65,10 @@
"This is a system app and can\'t be uninstalled."
"Unnamed Folder"
"Disabled %1$s"
-
+
+ - %1$s, has %2$d notifications
+ - %1$s, has %2$d notification
+
"Page %1$d of %2$d"
"Home screen %1$d of %2$d"
"New home screen page"
@@ -82,17 +84,13 @@
"Disabled by your admin"
"Allow Homescreen rotation"
"When phone is rotated"
-
-
-
-
-
-
+ "Notification dots"
+ "On"
+ "Off"
"Notification access needed"
"To show Notification Dots, turn on app notifications for %1$s"
"Change settings"
-
-
+ "Show notification dots"
"Add icon to Home screen"
"For new apps"
"Change icon shape"
diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml
index b1fd75be7f..f88f8fca73 100644
--- a/res/values-es-rUS/strings.xml
+++ b/res/values-es-rUS/strings.xml
@@ -39,8 +39,7 @@
"Cargando apps…"
"No hay apps que coincidan con \"%1$s\""
"Buscar más apps"
-
-
+ "App"
"Notificaciones"
"Mantén presionado para elegir un acceso directo."
"Presiona dos veces y mantén presionado para elegir un acceso directo o usar acciones personalizadas."
@@ -66,7 +65,10 @@
"Esta es una aplicación del sistema y no se puede desinstalar."
"Carpeta sin nombre"
"Se inhabilitó %1$s"
-
+
+ - %1$s tiene %2$d notificaciones
+ - %1$s tiene %2$d notificación
+
"Página %1$d de %2$d"
"Pantalla principal %1$d de %2$d"
"Nueva página en la pantalla principal"
@@ -82,17 +84,13 @@
"El administrador inhabilitó esta función"
"Permitir la rotación de la pantalla principal"
"Al girar el teléfono"
-
-
-
-
-
-
+ "Puntos de notificación"
+ "Activado"
+ "Desactivado"
"Se necesita acceso a las notificaciones"
"Para mostrar los puntos de notificación, activa las notificaciones de la app para %1$s"
"Cambiar la configuración"
-
-
+ "Mostrar puntos de notificación"
"Agregar ícono a la pantalla principal"
"Para nuevas apps"
"Cambiar forma de los íconos"
diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml
index 3021c71b31..3f3322c400 100644
--- a/res/values-es/strings.xml
+++ b/res/values-es/strings.xml
@@ -39,8 +39,7 @@
"Cargando aplicaciones…"
"No se han encontrado aplicaciones que contengan \"%1$s\""
"Buscar más aplicaciones"
-
-
+ "Aplicación"
"Notificaciones"
"Mantén pulsado para elegir un acceso directo."
"Toca dos veces y mantén pulsado para elegir un acceso directo o utilizar acciones personalizadas."
@@ -66,7 +65,10 @@
"Esta aplicación es del sistema y no se puede desinstalar."
"Carpeta sin nombre"
"Se ha inhabilitado %1$s"
-
+
+ - %1$s tiene %2$d notificaciones
+ - %1$s tiene %2$d notificación
+
"Página %1$d de %2$d"
"Pantalla de inicio %1$d de %2$d"
"Nueva página de pantalla de inicio"
@@ -82,17 +84,13 @@
"Inhabilitado por el administrador"
"Permitir rotación de la pantalla de inicio"
"Al girar el teléfono"
-
-
-
-
-
-
+ "Burbujas de notificación"
+ "Activadas"
+ "Desactivadas"
"Se necesita acceso a las notificaciones"
"Para mostrar burbujas de notificación, activa las notificaciones de %1$s"
"Cambiar ajustes"
-
-
+ "Mostrar burbujas de notificación"
"Añadir icono a la pantalla de inicio"
"Para aplicaciones nuevas"
"Cambiar forma de los iconos"
diff --git a/res/values-et/strings.xml b/res/values-et/strings.xml
index f3c14a36c5..ea04cdda7b 100644
--- a/res/values-et/strings.xml
+++ b/res/values-et/strings.xml
@@ -39,8 +39,7 @@
"Rakenduste laadimine …"
"Päringule „%1$s” ei vastanud ükski rakendus"
"Otsi rohkem rakendusi"
-
-
+ "Rakendus"
"Märguanded"
"Otsetee valimiseks puudutage seda pikalt."
"Topeltpuudutage ja hoidke otsetee valimiseks või kohandatud toimingute kasutamiseks."
@@ -66,7 +65,10 @@
"See on süsteemirakendus ja seda ei saa desinstallida."
"Nimetu kaust"
"Rakendus %1$s on keelatud"
-
+
+ - %1$s, %2$d märguannet
+ - %1$s, %2$d märguanne
+
"Leht %1$d/%2$d"
"Avaekraan %1$d/%2$d"
"Uus avaekraan"
@@ -82,17 +84,13 @@
"Keelas administraator"
"Luba avaekraani pööramine"
"Kui telefoni pööratakse"
-
-
-
-
-
-
+ "Märguandetäpid"
+ "Sees"
+ "Väljas"
"Vaja on juurdepääsu märguannetele"
"Märguandetäppide kuvamiseks lülitage sisse rakenduse %1$s märguanded"
"Seadete muutmine"
-
-
+ "Kuva märguandetäpid"
"Lisa ikoon avaekraanile"
"Uute rakenduste puhul"
"Ikooni kuju muutmine"
diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml
index c24ebec249..539c7599c7 100644
--- a/res/values-fa/strings.xml
+++ b/res/values-fa/strings.xml
@@ -39,8 +39,7 @@
"درحال بارگیری برنامهها…"
"هیچ برنامهای در مطابقت با «%1$s» پیدا نشد"
"جستجوی برنامههای بیشتر"
-
-
+ "برنامه"
"اعلانها"
"برای انتخاب میانبر، لمس کنید و نگهدارید."
"برای انتخاب میانبر، دو ضربه سریع بزنید و نگهدارید یا از کنشهای سفارشی استفاده کنید."
@@ -66,7 +65,10 @@
"این برنامه سیستمی است و حذف نصب نمیشود."
"پوشه بینام"
"%1$s غیرفعال شد"
-
+
+ - %1$s، %2$d اعلان دارد
+ - %1$s، %2$d اعلان دارد
+
"صفحه %1$d از %2$d"
"صفحه اصلی %1$d از %2$d"
"صفحه اصلی جدید"
@@ -82,17 +84,13 @@
"توسط سرپرست سیستم غیرفعال شده است"
"امکان دادن به چرخش صفحه اصلی"
"وقتی تلفن چرخانده میشود"
-
-
-
-
-
-
+ "نقطههای اعلان"
+ "روشن"
+ "خاموش"
"دسترسی به اعلان نیاز است"
"برای نمایش «نقطههای اعلان»، اعلانهای برنامه را برای %1$s روشن کنید"
"تغییر تنظیمات"
-
-
+ "نمایش نقطههای اعلان"
"افزودن نماد به صفحه اصلی"
"برای برنامههای جدید"
"تغییر شکل نماد"
diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml
index 5cc6a5a477..70853bd235 100644
--- a/res/values-fi/strings.xml
+++ b/res/values-fi/strings.xml
@@ -39,8 +39,7 @@
"Ladataan sovelluksia…"
"%1$s ei palauttanut sovelluksia."
"Hae lisää sovelluksia"
-
-
+ "Sovellus"
"Ilmoitukset"
"Valitse pikakuvake painamalla sitä pitkään."
"Valitse pikakuvake tai käytä muokattuja toimintoja kaksoisnapauttamalla ja painamalla pitkään."
@@ -66,7 +65,10 @@
"Tämä on järjestelmäsovellus, eikä sitä voi poistaa."
"Nimetön kansio"
"%1$s poistettiin käytöstä"
-
+
+ - %1$s: %2$d ilmoitusta
+ - %1$s: %2$d ilmoitus
+
"Sivu %1$d / %2$d"
"Aloitusruutu %1$d/%2$d"
"Uusi aloitusnäytön sivu"
@@ -82,17 +84,13 @@
"Järjestelmänvalvoja on poistanut toiminnon käytöstä."
"Salli aloitusnäytön kiertäminen"
"Kun puhelinta kierretään"
-
-
-
-
-
-
+ "Pistemerkit"
+ "Käytössä"
+ "Ei käytössä"
"Ilmoituksien käyttöoikeus tarvitaan"
"%1$s tarvitsee ilmoitusten käyttöoikeuden, jotta pistemerkkejä voidaan näyttää."
"Muuta asetuksia"
-
-
+ "Näytä ilmoituksista kertovat pistemerkit"
"Lisää kuvake aloitusruutuun"
"Uusille sovelluksille"
"Muuta kuvakkeen muotoa"
diff --git a/res/values-fr-rCA/strings.xml b/res/values-fr-rCA/strings.xml
index f82ea47462..2a70d3d153 100644
--- a/res/values-fr-rCA/strings.xml
+++ b/res/values-fr-rCA/strings.xml
@@ -39,8 +39,7 @@
"Chargement des applications en cours…"
"Aucune application trouvée correspondant à « %1$s »"
"Rechercher plus d\'applications"
-
-
+ "Application"
"Notifications"
"Maintenez un doigt sur le raccourci pour l\'ajouter"
"Touchez 2x un raccourci et maintenez doigt dessus pour l’aj. ou utiliser des actions personnalisées."
@@ -66,7 +65,10 @@
"Impossible de désinstaller cette application, car il s\'agit d\'une application système."
"Dossier sans nom"
"L\'application %1$s est désactivée"
-
+
+ - %1$s a %2$d notification
+ - %1$s a %2$d notifications
+
"Page %1$d sur %2$d"
"Écran d\'accueil %1$d sur %2$d"
"Nouvelle page d\'écran d\'accueil"
@@ -82,17 +84,13 @@
"Cette fonction est désactivée par votre administrateur"
"Autoriser la rotation de l\'écran d\'accueil"
"Lorsque vous faites pivoter le téléphone"
-
-
-
-
-
-
+ "Points de notification"
+ "Activé"
+ "Désactivé"
"L\'accès aux notifications est requis"
"Pour afficher les points de notification, activez les notifications d\'application pour %1$s"
"Modifier les paramètres"
-
-
+ "Afficher les points de notification"
"Ajouter l\'icône à l\'écran d\'accueil"
"Pour les nouvelles applications"
"Modifier la forme de l\'icône"
diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml
index 1d2e743d9d..35b8ca655f 100644
--- a/res/values-fr/strings.xml
+++ b/res/values-fr/strings.xml
@@ -39,8 +39,7 @@
"Chargement des applications…"
"Aucune application ne correspond à la requête \"%1$s\""
"Rechercher plus d\'applications"
-
-
+ "Application"
"Notifications"
"Appui prolongé pour sélectionner un raccourci."
"Appuyez 2X et maintenez la pression pour choisir un raccourci ou utilisez les actions personnalisées"
@@ -66,7 +65,10 @@
"Impossible de désinstaller cette application, car il s\'agit d\'une application système."
"Dossier sans nom"
"%1$s est désactivé."
-
+
+ - %1$s comporte %2$d notification
+ - %1$s comporte %2$d notifications
+
"Page %1$d sur %2$d"
"Écran d\'accueil %1$d sur %2$d"
"Nouvelle page d\'écran d\'accueil"
@@ -82,17 +84,13 @@
"Désactivé par votre administrateur"
"Autoriser la rotation de l\'écran d\'accueil"
"Lorsque vous faites pivoter le téléphone"
-
-
-
-
-
-
+ "Pastilles de notification"
+ "Activées"
+ "Désactivées"
"Accès aux notifications requis"
"Pour afficher les pastilles de notification, activez les notifications de l\'application %1$s"
"Modifier les paramètres"
-
-
+ "Afficher les pastilles de notification"
"Ajouter l\'icône à l\'écran d\'accueil"
"Pour les nouvelles applications"
"Modifier la forme des icônes"
diff --git a/res/values-gl/strings.xml b/res/values-gl/strings.xml
index 7e1788ad03..4a9f8dc6d7 100644
--- a/res/values-gl/strings.xml
+++ b/res/values-gl/strings.xml
@@ -39,8 +39,7 @@
"Cargando aplicacións…"
"Non se atoparon aplicacións que coincidan con \"%1$s\""
"Buscar máis aplicacións"
-
-
+ "Aplicación"
"Notificacións"
"Mantén premido un atallo para seleccionalo."
"Toca dúas veces e mantén premido para seleccionar un atallo ou utiliza accións personalizadas."
@@ -66,7 +65,10 @@
"Esta aplicación é do sistema e non se pode desinstalar."
"Cartafol sen nome"
"Desactivouse %1$s"
-
+
+ - A aplicación %1$s ten %2$d notificacións
+ - A aplicación %1$s ten %2$d notificación
+
"Páxina %1$d de %2$d"
"Pantalla de inicio %1$d de %2$d"
"Nova páxina da pantalla de inicio"
@@ -82,17 +84,13 @@
"Función desactivada polo administrador"
"Permitir xirar a pantalla de inicio"
"Ao xirar o teléfono"
-
-
-
-
-
-
+ "Puntos de notificacións"
+ "Opción activada"
+ "Opción desactivada"
"Necesítase acceso ás notificacións"
"Para que se mostren os puntos de notificacións, activa as notificacións da aplicación %1$s"
"Cambiar configuración"
-
-
+ "Mostrar puntos de notificacións"
"Engadir icona á pantalla de inicio"
"Para novas aplicacións"
"Cambiar forma das iconas"
diff --git a/res/values-gu/strings.xml b/res/values-gu/strings.xml
index 0db294f402..d0f7cc3f24 100644
--- a/res/values-gu/strings.xml
+++ b/res/values-gu/strings.xml
@@ -39,8 +39,7 @@
"ઍપ્લિકેશનો લોડ કરી રહ્યું છે…"
"\"%1$s\"થી મેળ ખાતી કોઈ ઍપ્લિકેશનો મળી નથી"
"વધુ ઍપ્લિકેશનો શોધો"
-
-
+ "ઍપ"
"નોટિફિકેશનો"
"એક શૉર્ટકટ ચૂંટવા માટે સ્પર્શ કરી રાખો."
"એક શૉર્ટકટ ચૂંટવા અથવા કોઈ કસ્ટમ ક્રિયાઓનો ઉપયોગ કરવા માટે બે વાર ટૅપ કરીને દબાવી રાખો."
@@ -66,7 +65,10 @@
"આ એક સિસ્ટમ ઍપ્લિકેશન છે અને અનઇન્સ્ટોલ કરી શકાતી નથી."
"અનામી ફોલ્ડર"
"%1$s અક્ષમ કરી"
-
+
+ - %1$sના %2$d નોટિફિકેશન છે
+ - %1$sના %2$d નોટિફિકેશન છે
+
"%2$d માંથી %1$d પૃષ્ઠ"
"%2$d માંથી %1$d હોમ સ્ક્રીન"
"નવું હોમ સ્ક્રીન પૃષ્ઠ"
@@ -82,17 +84,13 @@
"તમારા વ્યવસ્થાપક દ્વારા અક્ષમ કરેલ"
"હોમ સ્ક્રીનને ફેરવવાની મંજૂરી આપો"
"જ્યારે ફોન ફેરવવામાં આવે ત્યારે"
-
-
-
-
-
-
+ "નોટિફિકેશન માટેના ચિહ્નો"
+ "ચાલુ છે"
+ "બંધ છે"
"નોટિફિકેશનનો ઍક્સેસની જરૂરી છે"
"નોટિફિકેશન માટેનું ચિહ્ન બતાવવા હેતુ, %1$s માટેની ઍપ્લિકેશન નોટિફિકેશન ચાલુ કરો"
"સેટિંગ્સ બદલો"
-
-
+ "નોટિફિકેશન માટેના ચિહ્ન બતાવો"
"હોમ સ્ક્રીન પર આઇકન ઉમેરો"
"નવી ઍપ્લિકેશનો માટે"
"આઇકનનો આકાર બદલો"
diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml
index 992122625d..b37b17c8d2 100644
--- a/res/values-hi/strings.xml
+++ b/res/values-hi/strings.xml
@@ -39,8 +39,7 @@
"ऐप्लिकेशन लोड हो रहे हैं…"
"\"%1$s\" से मिलता-जुलता कोई ऐप्लिकेशन नहीं मिला"
"और ऐप सर्च करें"
-
-
+ "ऐप्लिकेशन"
"सूचनाएं"
"शॉर्टकट चुनने के लिए दबाकर रखें."
"शॉर्टकट चुनने या पसंद के मुताबिक कार्रवाई करने के लिए दो बार टैप करें और कुछ देर दबाए रखें."
@@ -52,7 +51,7 @@
"होम पेज"
"निकालें"
"अनइंस्टॉल करें"
- "ऐप की जानकारी"
+ "ऐप्लिकेशन की जानकारी"
"इंस्टॉल करें"
"शॉर्टकट इंस्टॉल करें"
"ऐप को उपयोगकर्ता के हस्तक्षेप के बिना शॉर्टकट जोड़ने देती है."
@@ -66,7 +65,10 @@
"यह एक सिस्टम ऐप्लिकेशन है और इसे अनइंस्टॉल नहीं किया जा सकता."
"अनामित फ़ोल्डर"
"%1$s अक्षम है"
-
+
+ - %1$s की %2$d सूचना है
+ - %1$s की %2$d सूचनाएं हैं
+
"पेज %2$d में से %1$d"
"होम स्क्रीन %2$d में से %1$d"
"नया होम स्क्रीन पेज"
@@ -82,17 +84,13 @@
"आपके एडमिन ने बंद किया हुआ है"
"होमस्क्रीन घुमाने की अनुमति दें"
"फ़ोन घुुमाए जाने पर"
-
-
-
-
-
-
+ "नई सूचनाएं बताने वाला गोल निशान"
+ "चालू"
+ "चालू"
"सूचना के एक्सेस की ज़रूरत है"
"सूचना बिंदु दिखाने के लिए, %1$s के ऐप्लिकेशन सूचना चालू करें"
"सेटिंग बदलें"
-
-
+ "नई सूचनाएं बताने वाला गोल निशान दिखाएं"
"होम स्क्रीन में आइकॉन जोड़ें"
"नए ऐप्लिकेशन के लिए"
"आइकॉन का आकार बदलें"
diff --git a/res/values-hr/strings.xml b/res/values-hr/strings.xml
index 26dc811be2..1d1919b30a 100644
--- a/res/values-hr/strings.xml
+++ b/res/values-hr/strings.xml
@@ -39,8 +39,7 @@
"Učitavanje aplikacija…"
"Nema aplikacija podudarnih s upitom \"%1$s\""
"Traži više aplikacija"
-
-
+ "Aplikacija"
"Obavijesti"
"Dodirnite i zadržite kako biste podigli prečac."
"Dvaput dodirnite i zadržite pritisak kako biste podigli prečac ili pokušajte prilagođenim radnjama."
@@ -66,7 +65,11 @@
"Ovo je aplikacija sustava i ne može se ukloniti."
"Neimenovana mapa"
"Aplikacija %1$s onemogućena"
-
+
+ - %1$s, ima %2$d obavijest
+ - %1$s, ima %2$d obavijesti
+ - %1$s, ima %2$d obavijesti
+
"Stranica %1$d od %2$d"
"Početni zaslon %1$d od %2$d"
"Nova stranica početnog zaslona"
@@ -82,17 +85,13 @@
"Onemogućio administrator"
"Dopusti zakretanje početnog zaslona"
"Kada se telefon zakrene"
-
-
-
-
-
-
+ "Točke obavijesti"
+ "Uključeno"
+ "Isključeno"
"Potreban je pristup obavijestima"
"Za prikaz točaka obavijesti uključite obavijesti aplikacije %1$s"
"Promjena postavki"
-
-
+ "Prikaži točke obavijesti"
"Dodaj ikonu na početni zaslon"
"Za nove aplikacije"
"Promijeni oblik ikona"
diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml
index b005f3ee8a..9f965bc4a2 100644
--- a/res/values-hu/strings.xml
+++ b/res/values-hu/strings.xml
@@ -39,8 +39,7 @@
"Alkalmazások betöltése…"
"Nem található alkalmazás a(z) „%1$s” lekérdezésre"
"További alkalmazások keresése"
-
-
+ "Alkalmazás"
"Értesítések"
"Felvételhez tartsa nyomva a parancsikont."
"Parancsikon felvételéhez koppintson rá duplán és tartsa nyomva, vagy használjon egyéni műveleteket."
@@ -66,7 +65,10 @@
"Ez egy rendszeralkalmazás, és nem lehet eltávolítani."
"Névtelen mappa"
"A(z) %1$s letiltva"
-
+
+ - A(z) %1$s %2$d értesítéssel rendelkezik
+ - A(z) %1$s %2$d értesítéssel rendelkezik
+
"%2$d/%1$d. oldal"
"%2$d/%1$d. kezdőképernyő"
"Új kezdőképernyő oldal"
@@ -82,17 +84,13 @@
"A rendszergazda letiltotta"
"A kezdőképernyő elforgatásának engedélyezése"
"A telefon elforgatásakor"
-
-
-
-
-
-
+ "Értesítési pöttyök"
+ "Be"
+ "Ki"
"Értesítésekhez való hozzáférésre van szükség"
"Az értesítési pöttyök megjelenítéséhez kapcsolja be a(z) %1$s alkalmazás értesítéseit"
"Beállítások módosítása"
-
-
+ "Értesítési pöttyök megjelenítése"
"Ikon hozzáadása a kezdőképernyőhöz"
"Új alkalmazásoknál"
"Ikon formájának módosítása"
diff --git a/res/values-hy/strings.xml b/res/values-hy/strings.xml
index 6239ecdbd0..ca56102723 100644
--- a/res/values-hy/strings.xml
+++ b/res/values-hy/strings.xml
@@ -39,8 +39,7 @@
"Հավելվածների բեռնում…"
"«%1$s» հարցմանը համապատասխանող հավելվածներ չեն գտնվել"
"Որոնել այլ հավելվածներ"
-
-
+ "Հավելված"
"Ծանուցումներ"
"Կրկնակի հպեք և պահեք՝ դյուրանցում ընտրելու համար։"
"Կրկնակի հպեք և պահեք՝ դյուրանցում ընտրելու համար կամ օգտվեք հարմարեցրած գործողություններից:"
@@ -66,7 +65,10 @@
"Սա համակարգային ծրագիր է և չի կարող ապատեղադրվել:"
"Անանուն պանակ"
"%1$s հավելվածն անջատված է"
-
+
+ - %1$s, ունի %2$d ծանուցում
+ - %1$s, ունի %2$d ծանուցում
+
"Էջ %1$d՝ %2$d-ից"
"Հիմնական էկրան %1$d` %2$d-ից"
"Հիմնական էկրանի նոր էջ"
@@ -82,17 +84,13 @@
"Անջատվել է ձեր ադմինիստրատորի կողմից"
"Թույլ տալ հիմնական էկրանի պտտումը"
"Հեռախոսը պտտելու դեպքում"
-
-
-
-
-
-
+ "Ծանուցումների կետիկներ"
+ "Միացված է"
+ "Անջատած է"
"Անհրաժեշտ է ծանուցման թույլտվություն"
"Ծանուցումների կետիկները ցուցադրելու համար միացրեք ծանուցումները %1$s-ի համար"
"Փոխել կարգավորումները"
-
-
+ "Ցուցադրել ծանուցումների կետիկները"
"Ավելացնել պատկերակը Հիմնական էկրանին"
"Նոր հավելվածների համար"
"Փոխել պատկերակների տեսքը"
diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml
index 9f58265e6d..396c5b164b 100644
--- a/res/values-in/strings.xml
+++ b/res/values-in/strings.xml
@@ -39,8 +39,7 @@
"Memuat aplikasi…"
"Tidak ditemukan aplikasi yang cocok dengan \"%1$s\""
"Telusuri aplikasi lainnya"
-
-
+ "Aplikasi"
"Notifikasi"
"Tap lama untuk memilih pintasan."
"Tap dua kali & tahan untuk memilih pintasan atau menggunakan tindakan khusus."
@@ -66,7 +65,10 @@
"Ini adalah aplikasi sistem dan tidak dapat dicopot pemasangannya."
"Folder Tanpa Nama"
"%1$s dinonaktifkan"
-
+
+ - %1$s, memiliki %2$d notifikasi
+ - %1$s, memiliki %2$d notifikasi
+
"Halaman %1$d dari %2$d"
"Layar utama %1$d dari %2$d"
"Halaman layar utama baru"
@@ -82,17 +84,13 @@
"Dinonaktifkan oleh admin"
"Izinkan layar Utama diputar"
"Saat ponsel diputar"
-
-
-
-
-
-
+ "Titik notifikasi"
+ "Aktif"
+ "Nonaktif"
"Perlu akses notifikasi"
"Guna menampilkan Titik Notifikasi, aktifkan notifikasi aplikasi untuk %1$s"
"Ubah setelan"
-
-
+ "Tampilkan titik notifikasi"
"Tambahkan ikon ke Layar utama"
"Untuk aplikasi baru"
"Ubah bentuk ikon"
diff --git a/res/values-is/strings.xml b/res/values-is/strings.xml
index 2826861ffd..99bd888ade 100644
--- a/res/values-is/strings.xml
+++ b/res/values-is/strings.xml
@@ -39,8 +39,7 @@
"Hleður forrit…"
"Ekki fundust forrit sem samsvara „%1$s“"
"Leita að fleiri forritum"
-
-
+ "Forrit"
"Tilkynningar"
"Haltu fingri á flýtileið til að grípa hana."
"Ýttu tvisvar og haltu fingri á flýtileið til að grípa hana eða notaðu sérsniðnar aðgerðir."
@@ -66,7 +65,10 @@
"Þetta er kerfisforrit sem ekki er hægt að fjarlægja."
"Ónefnd mappa"
"Óvirkt %1$s"
-
+
+ - %1$s, er með %2$d tilkynningu
+ - %1$s, er með %2$d tilkynningar
+
"Síða %1$d af %2$d"
"Heimaskjár %1$d af %2$d"
"Ný síða á heimaskjá"
@@ -82,17 +84,13 @@
"Gert óvirkt af kerfisstjóra"
"Leyfa snúning fyrir heimaskjá"
"Þegar símanum er snúið"
-
-
-
-
-
-
+ "Tilkynningapunktar"
+ "Kveikt"
+ "Slökkt"
"Aðgangs að tilkynningum er krafist"
"Til að sýna tilkynningarpunkta skaltu kveikja á forritstilkynningum fyrir %1$s"
"Breyta stillingum"
-
-
+ "Sýna tilkynningapunkta"
"Bæta tákni á heimaskjáinn"
"Fyrir ný forrit"
"Breyta formi tákns"
diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml
index 825f914fe5..0bdc5afc97 100644
--- a/res/values-it/strings.xml
+++ b/res/values-it/strings.xml
@@ -39,8 +39,7 @@
"Caricamento delle app…"
"Nessuna app trovata corrispondente a \"%1$s\""
"Cerca altre app"
-
-
+ "App"
"Notifiche"
"Tocca e tieni premuto per scegliere la scorciatoia"
"Tocca due volte e tieni premuto per scegliere una scorciatoia o per usare azioni personalizzate."
@@ -66,7 +65,10 @@
"Questa è un\'app di sistema e non può essere disinstallata."
"Cartella senza nome"
"App %1$s disattivata"
-
+
+ - %1$s, ha %2$d notifiche
+ - %1$s, ha %2$d notifica
+
"Pagina %1$d di %2$d"
"Schermata Home %1$d di %2$d"
"Nuova pagina Schermata Home"
@@ -82,17 +84,13 @@
"Disattivata dall\'amministratore"
"Consenti rotazione della schermata Home"
"Con il telefono ruotato"
-
-
-
-
-
-
+ "Indicatori di notifica"
+ "On"
+ "Off"
"Accesso alle notifiche necessario"
"Per mostrare gli indicatori di notifica, attiva le notifiche per l\'app %1$s"
"Modifica impostazioni"
-
-
+ "Mostra indicatori di notifica"
"Aggiungi icone alla schermata Home"
"Per le nuove app"
"Cambia la forma delle icone"
diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml
index 6104bc0d19..9525468f68 100644
--- a/res/values-iw/strings.xml
+++ b/res/values-iw/strings.xml
@@ -39,8 +39,7 @@
"טוען אפליקציות…"
"לא נמצאו אפליקציות התואמות ל-\"%1$s\""
"חפש אפליקציות נוספות"
-
-
+ "אפליקציה"
"התראות"
"כדי להוסיף קיצור דרך, יש לגעת בו ולהחזיק אותו."
"כדי להוסיף קיצור דרך או להשתמש בפעולות מותאמות אישית, יש להקיש על קיצור הדרך פעמיים ולהחזיק אותו."
@@ -66,7 +65,12 @@
"זוהי אפליקציית מערכת ולא ניתן להסיר את התקנתה."
"תיקיה ללא שם"
"%1$s מושבתת"
-
+
+ - לאפליקציה %1$s יש %2$d התראות
+ - לאפליקציה %1$s יש %2$d התראות
+ - לאפליקציה %1$s יש %2$d התראות
+ - לאפליקציה %1$s יש התראה אחת (%2$d)
+
"דף %1$d מתוך %2$d"
"מסך דף הבית %1$d מתוך %2$d"
"מסך דף הבית חדש"
@@ -82,17 +86,13 @@
"הושבת על ידי מנהל המערכת שלך"
"אפשרות סיבוב של מסך דף הבית"
"כאשר הטלפון מסובב"
-
-
-
-
-
-
+ "סימני ההתראות"
+ "מופעל"
+ "כבוי"
"נדרשת גישה להתראות"
"כדי להציג את סימני ההתראות,יש להפעיל התראות מהאפליקציה %1$s"
"שנה את ההגדרות"
-
-
+ "הצגת סימני ההתראות"
"הוספת סמל במסך דף הבית"
"לאפליקציות חדשות"
"שינוי הצורה של הסמלים"
diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml
index 089b938d51..2c5da02c38 100644
--- a/res/values-ja/strings.xml
+++ b/res/values-ja/strings.xml
@@ -39,8 +39,7 @@
"アプリを読み込んでいます…"
"「%1$s」に一致するアプリは見つかりませんでした"
"他のアプリを検索"
-
-
+ "アプリ"
"通知"
"ショートカットを追加するには押し続けます。"
"ダブルタップ後に押し続けてショートカットを選択するか、カスタム操作を使用してください。"
@@ -66,7 +65,10 @@
"このシステムアプリはアンインストールできません。"
"名前のないフォルダ"
"「%1$s」は無効です"
-
+
+ - %1$s の通知が %2$d 件あります
+ - %1$s の通知が %2$d 件あります
+
"%1$d/%2$dページ"
"ホーム画面: %1$d/%2$d"
"新しいホーム画面ページ"
@@ -82,17 +84,13 @@
"管理者により無効にされています"
"ホーム画面の回転を許可"
"スマートフォンが回転したとき"
-
-
-
-
-
-
+ "通知ドット"
+ "ON"
+ "OFF"
"通知へのアクセス権限が必要"
"通知ドットを表示するには、「%1$s」のアプリ通知を ON にしてください"
"設定を変更"
-
-
+ "通知ドットの表示"
"ホーム画面にアイコンを追加"
"新しいアプリをダウンロードしたとき"
"アイコンの形の変更"
diff --git a/res/values-ka/strings.xml b/res/values-ka/strings.xml
index fef1a48689..af603c86e0 100644
--- a/res/values-ka/strings.xml
+++ b/res/values-ka/strings.xml
@@ -39,8 +39,7 @@
"აპები იტვირთება…"
"„%1$s“-ის თანხვედრი აპები არ მოიძებნა"
"მეტი აპის პოვნა"
-
-
+ "აპი"
"შეტყობინებები"
"შეეხეთ და დააყოვნეთ მალსახმობის ასარჩევად."
"ორმაგად შეეხეთ და გეჭიროთ მალსახმობის ასარჩევად ან მორგებული მოქმედებების გამოსაყენებლად."
@@ -66,7 +65,10 @@
"ეს სისტემური აპია და მისი წაშლა შეუძლებელია."
"უსახელო საქაღალდე"
"%1$s გაითიშა"
-
+
+ - %1$s-ში არის %2$d შეტყობინება
+ - %1$s-ში არის %2$d შეტყობინება
+
"გვერდი %1$d %2$d-დან"
"მთავარი ეკრანი %1$d, %2$d-დან"
"მთავარი ეკრანის ახალი გვერდი"
@@ -82,17 +84,13 @@
"გათიშულია თქვენი ადმინისტრატორის მიერ"
"მთავარი ეკრანის შეტრიალების დაშვება"
"ტელეფონის შეტრიალებისას"
-
-
-
-
-
-
+ "შეტყობინების ნიშნულები"
+ "ჩართულია"
+ "გამორთულია"
"საჭიროა შეტყობინებებზე წვდომა"
"შეტყობინებათა ნიშნულების საჩვენებლად, ჩართეთ აპის შეტყობინებები %1$s-ისთვის"
"პარამეტრების შეცვლა"
-
-
+ "შეტყობინების ნიშნულების ჩვენება"
"ხატულას მთავარ ეკრანზე დამატება"
"ახალი აპებისთვის"
"ხატულას ფორმის შეცვლა"
diff --git a/res/values-kk/strings.xml b/res/values-kk/strings.xml
index dd26eab103..135360e722 100644
--- a/res/values-kk/strings.xml
+++ b/res/values-kk/strings.xml
@@ -39,8 +39,7 @@
"Қолданбалар жүктелуде…"
"\"%1$s\" сұрауына сәйкес келетін қолданбалар жоқ"
"Қосымша қолданбалар іздеу"
-
-
+ "Қолданба"
"Хабарландырулар"
"Таңбашаны таңдау үшін оны басып, ұстап тұрыңыз."
"Екі рет басып, ұстап тұрып, таңбашаны таңдаңыз немесе арнаулы әрекеттерді пайдаланыңыз."
@@ -66,7 +65,10 @@
"Бұл жүйе қолданбасы, сондықтан оны алу мүмкін емес."
"Атауы жоқ қалта"
"%1$s өшірілді"
-
+
+ - %1$s қолданбасында %2$d хабарландыру бар
+ - %1$s қолданбасында %2$d хабарландыру бар
+
"%1$d бет, барлығы %2$d"
"%1$d негізгі экран, барлығы %2$d"
"Жаңа негізгі экран беті"
@@ -82,17 +84,13 @@
"Әкімші өшірді"
"Негізгі экранның бұрылуына рұқсат ету"
"Телефон бұрылғанда"
-
-
-
-
-
-
+ "Хабарландыру белгілері"
+ "Қосулы"
+ "Өшірулі"
"Хабарландыруға кіру рұқсаты қажет"
"Хабарландыру белгілерін көрсету үшін %1$s қолданбасының қолданба хабарландыруларын қосыңыз"
"Параметрлерді өзгерту"
-
-
+ "Хабарландыру белгілерін көрсету"
"Негізгі экранға белгіше енгізу"
"Жаңа қолданбаларға арналған"
"Белгіше пішінін өзгерту"
diff --git a/res/values-km/strings.xml b/res/values-km/strings.xml
index c6e0ba4831..d7c8c8895b 100644
--- a/res/values-km/strings.xml
+++ b/res/values-km/strings.xml
@@ -39,8 +39,7 @@
"កំពុងផ្ទុកកម្មវិធី…"
"រកមិនឃើញកម្មវិធីដែលត្រូវគ្នាជាមួយ \"%1$s\" ទេ"
"ស្វែងរកកម្មវិធីច្រើនទៀត"
-
-
+ "កម្មវិធី"
"ការជូនដំណឹង"
"ចុចឱ្យជាប់ដើម្បីជ្រើសរើសផ្លូវកាត់មួយ។"
"ចុចពីរដង ហើយចុចឱ្យជាប់ដើម្បីជ្រើសរើសផ្លូវកាត់មួយ ឬប្រើសកម្មភាពផ្ទាល់ខ្លួន។"
@@ -66,7 +65,10 @@
"នេះជាកម្មវិធីប្រព័ន្ធ មិនអាចលុបបានទេ។"
"ថតគ្មានឈ្មោះ"
"បានបិទដំណើរការ %1$s"
-
+
+ - %1$s, មានការជូនដំណឹង %2$d
+ - %1$s, មានការជូនដំណឺង %2$d
+
"ទំព័រ %1$d នៃ %2$d"
"អេក្រង់ដើម %1$d នៃ %2$d"
"ទំព័រអេក្រង់ដើមថ្មី"
@@ -82,17 +84,13 @@
"បានបិទដំណើរការដោយអ្នកគ្រប់គ្រងរបស់អ្នក"
"អនុញ្ញាតការបងិ្វលអេក្រង់ដើម"
"នៅពេលដែលបង្វិលទូរស័ព្ទរបស់អ្នក"
-
-
-
-
-
-
+ "ស្លាកជូនដំណឹង"
+ "បើក"
+ "បិទ"
"តម្រូវឲ្យមានសិទ្ធិចូលប្រើប្រាស់ការជូនដំណឹង"
"ដើម្បីបង្ហាញស្លាកជូនដំណឹង សូមបើកការជូនដំណឹងកម្មវិធីសម្រាប់ %1$s"
"ប្ដូរការកំណត់"
-
-
+ "បង្ហាញស្លាកជូនដំណឹង"
"បញ្ចូលរូបតំណាងទៅអេក្រង់ដើម"
"សម្រាប់កម្មវិធីថ្មី"
"ប្តូររូបរាងរូបតំណាង"
diff --git a/res/values-kn/strings.xml b/res/values-kn/strings.xml
index 965700e6a1..de9ee52cd3 100644
--- a/res/values-kn/strings.xml
+++ b/res/values-kn/strings.xml
@@ -39,8 +39,7 @@
"ಅಪ್ಲಿಕೇಶನ್ಗಳನ್ನು ಲೋಡ್ ಮಾಡಲಾಗುತ್ತಿದೆ..."
"\"%1$s\" ಹೊಂದಿಕೆಯ ಯಾವುದೇ ಅಪ್ಲಿಕೇಶನ್ಗಳು ಕಂಡುಬಂದಿಲ್ಲ"
"ಮತ್ತಷ್ಟು ಅಪ್ಲಿಕೇಶನ್ಗಳನ್ನು ಹುಡುಕಿ"
-
-
+ "ಆ್ಯಪ್"
"ಅಧಿಸೂಚನೆಗಳು"
"ಸ್ಪರ್ಶಿಸಿ ಮತ್ತು ಶಾರ್ಟ್ಕಟ್ ಆರಿಸಲು ಹೋಲ್ಡ್ ಮಾಡಿ."
"ಡಬಲ್ ಟ್ಯಾಪ್ ಮಾಡಿ ಮತ್ತು ಶಾರ್ಟ್ಕಟ್ ಆರಿಸಿಕೊಳ್ಳಲು ಹೋಲ್ಡ್ ಮಾಡಿ ಅಥವಾ ಕಸ್ಟಮ್ ಕ್ರಿಯೆಗಳನ್ನು ಬಳಸಿ."
@@ -66,7 +65,10 @@
"ಇದೊಂದು ಅಪ್ಲಿಕೇಶನ್ ಆಗಿದೆ ಮತ್ತು ಅಸ್ಥಾಪಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ."
"ಹೆಸರಿಲ್ಲದ ಫೋಲ್ಡರ್"
"%1$s ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ"
-
+
+ - %1$s, %2$d ಅಧಿಸೂಚನೆಗಳನ್ನು ಹೊಂದಿದೆ
+ - %1$s, %2$d ಅಧಿಸೂಚನೆಗಳನ್ನು ಹೊಂದಿದೆ
+
"%2$d ರಲ್ಲಿ %1$d ಪುಟ"
"%2$d ರಲ್ಲಿ %1$d ಮುಖಪುಟದ ಪರದೆ"
"ಹೊಸ ಮುಖಪುಟ ಪರದೆ"
@@ -82,17 +84,13 @@
"ನಿಮ್ಮ ನಿರ್ವಾಹಕರು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಿದ್ದಾರೆ"
"ಮುಖಪುಟ ತಿರುಗುವಿಕೆಯನ್ನು ಅನುಮತಿಸಿ"
"ಫೋನ್ ತಿರುಗಿಸಿದಾಗ"
-
-
-
-
-
-
+ "ಅಧಿಸೂಚನೆ ಡಾಟ್ಗಳು"
+ "ಆನ್ ಆಗಿದೆ"
+ "ಆಫ್ ಆಗಿದೆ"
"ಅಧಿಸೂಚನೆ ಪ್ರವೇಶ ಅಗತ್ಯವಿದೆ"
"ಅಧಿಸೂಚನೆ ಚುಕ್ಕೆಗಳನ್ನು ತೋರಿಸಲು, %1$s ಗೆ ಅಪ್ಲಿಕೇಶನ್ ಅಧಿಸೂಚನೆಗಳನ್ನು ಆನ್ ಮಾಡಿ"
"ಸೆಟ್ಟಿಂಗ್ಗಳನ್ನು ಬದಲಾಯಿಸಿ"
-
-
+ "ಅಧಿಸೂಚನೆ ಡಾಟ್ಗಳನ್ನು ತೋರಿಸಿ"
"ಮುಖಪುಟದ ಪರದೆಗೆ ಐಕಾನ್ ಸೇರಿಸಿ"
"ಹೊಸ ಅಪ್ಲಿಕೇಶನ್ಗಳಿಗೆ"
"ಐಕಾನ್ ಆಕಾರವನ್ನು ಬದಲಿಸಿ"
diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml
index 3ed09e5ef9..121f141112 100644
--- a/res/values-ko/strings.xml
+++ b/res/values-ko/strings.xml
@@ -39,8 +39,7 @@
"앱 로드 중…"
"\'%1$s\'과(와) 일치하는 앱이 없습니다."
"더 많은 앱 검색"
-
-
+ "앱"
"알림"
"바로가기를 선택하려면 길게 터치하세요."
"바로가기를 선택하려면 두 번 탭한 다음 길게 터치하거나 맞춤 동작을 사용하세요."
@@ -66,7 +65,10 @@
"시스템 앱은 제거할 수 없습니다."
"이름이 없는 폴더"
"%1$s 사용 안함"
-
+
+ - %1$s에 %2$d개의 알림이 있음
+ - %1$s에 %2$d개의 알림이 있음
+
"페이지 %1$d/%2$d"
"홈 화면 %1$d/%2$d"
"새로운 홈 화면 페이지"
@@ -82,17 +84,13 @@
"관리자가 사용 중지함"
"홈 화면 회전 허용"
"휴대전화 회전 시"
-
-
-
-
-
-
+ "알림 표시 점"
+ "사용"
+ "사용 안함"
"알림 액세스 권한 필요"
"알림 표시점을 표시하려면 %1$s의 앱 알림을 사용 설정하세요."
"설정 변경"
-
-
+ "알림 표시 점 보기"
"홈 화면에 아이콘 추가"
"새로 설치한 앱에 적용"
"아이콘 모양 변경"
diff --git a/res/values-ky/strings.xml b/res/values-ky/strings.xml
index 4db7c8d01c..301840c11f 100644
--- a/res/values-ky/strings.xml
+++ b/res/values-ky/strings.xml
@@ -39,8 +39,7 @@
"Колдонмолор жүктөлүүдө…"
"\"%1$s\" сурамына дал келген колдонмолор табылган жок"
"Көбүрөөк колдонмолорду издөө"
-
-
+ "Колдонмо"
"Билдирмелер"
"Кыска жолду тандоо үчүн басып туруңуз."
"Кыска жолду тандоо үчүн эки жолу таптап, кармап туруңуз же ыңгайлаштырылган аракеттерди колдонуңуз."
@@ -66,7 +65,10 @@
"Бул системдик колдонмо жана аны чечкенге болбойт."
"Аты жок фолдер"
"%1$s өчүрүлгөн"
-
+
+ - %1$s, %2$d билдирмеси бар
+ - %1$s, %2$d билдирмеси бар
+
"%2$d ичинен %1$d барак"
"Үй экраны %2$d ичинен %1$d"
"Жаңы башкы экран барагы"
@@ -82,17 +84,13 @@
"Администраторуңуз өчүрүп койгон"
"Башкы экранды айлантууга уруксат берүү"
"Телефон айланганда"
-
-
-
-
-
-
+ "Билдирмелер белгилери"
+ "Күйүк"
+ "Өчүк"
"Эскертмелерге уруксат берилиши керек"
"Эскертме белгилерин көрсөтүү максатында, %1$s үчүн колдонмонун эскертмелерин күйгүзүү керек"
"Жөндөөлөрдү өзгөртүү"
-
-
+ "Билдирмелер белгилерин көрсөтүү"
"Башкы экранга сүрөтчө кошуу"
"Жаңы колдонмолор үчүн"
"Сүрөтчөнүн формасын өзгөртүү"
diff --git a/res/values-land/dimens.xml b/res/values-land/dimens.xml
index f0021956a1..b2f357565f 100644
--- a/res/values-land/dimens.xml
+++ b/res/values-land/dimens.xml
@@ -31,7 +31,5 @@
5.5dp
-
- 0dp
16dp
diff --git a/res/values-lo/strings.xml b/res/values-lo/strings.xml
index 3c55a8712f..692e5afe97 100644
--- a/res/values-lo/strings.xml
+++ b/res/values-lo/strings.xml
@@ -39,8 +39,7 @@
"ກໍາລັງໂຫຼດແອັບ…"
"ບໍ່ພົບແອັບທີ່ກົງກັບ \"%1$s\""
"ຊອກຫາແອັບເພີ່ມເຕີມ"
-
-
+ "ແອັບ"
"ການແຈ້ງເຕືອນ"
"ແຕະຄ້າງໄວ້ເພື່ອຮັບປຸ່ມລັດ."
"ແຕະສອງເທື່ອຄ້າງໄວ້ເພື່ອຮັບປຸ່ມລັດ ຫຼື ໃຊ້ຄຳສັ່ງແບບກຳນົດເອງ."
@@ -66,7 +65,10 @@
"ນີ້ແມ່ນແອັບຯຂອງລະບົບ ແລະບໍ່ສາມາດຖອນການຕິດຕັ້ງອອກໄດ້."
"ໂຟນເດີຍັງບໍ່ຖືກຕັ້ງຊື່"
"ປິດການນຳໃຊ້ %1$s ແລ້ວ"
-
+
+ - %1$s, ມີ %2$d ການແຈ້ງເຕືອນ
+ - %1$s, ມີ %2$d ການແຈ້ງເຕືອນ
+
"ໜ້າ %1$d ຈາກ %2$d"
"ໜ້າຈໍຫຼັກ %1$d ໃນ %2$d"
"ໜ້າຂອງໜ້າຈໍຫຼັກໃໝ່"
@@ -82,17 +84,13 @@
"ຖືກປິດການນຳໃຊ້ໂດຍຜູ້ເບິ່ງແຍງລະບົບຂອງທ່ານ"
"ອະນຸຍາດໃຫ້ໝຸນໜ້າຈໍທຳອິດໄດ້"
"ເມື່ອໝຸນໂທລະສັບ"
-
-
-
-
-
-
+ "ຈຸດການແຈ້ງເຕືອນ"
+ "ເປີດ"
+ "ປິດ"
"ຕ້ອງໃຊ້ການເຂົ້າເຖິງການແຈ້ງເຕືອນ"
"ເພື່ອສະແດງຈຸດການແຈ້ງເຕືອນ, ໃຫ້ເປີດການແຈ້ງເຕືອນສຳລັບ %1$s"
"ບັນທຶກການຕັ້ງຄ່າ"
-
-
+ "ສະແດງຈຸດການແຈ້ງເຕືອນ"
"ເພີ່ມໄອຄອນໃສ່ໜ້າຈໍຫຼັກ"
"ສຳລັບແອັບໃໝ່"
"ປ່ຽນຮູບຮ່າງໄອຄອນ"
diff --git a/res/values-lt/strings.xml b/res/values-lt/strings.xml
index 592eb9d821..22d0c7be73 100644
--- a/res/values-lt/strings.xml
+++ b/res/values-lt/strings.xml
@@ -39,8 +39,7 @@
"Įkeliamos programos…"
"Nerasta jokių užklausą „%1$s“ atitinkančių programų"
"Ieškoti daugiau programų"
-
-
+ "Programa"
"Pranešimai"
"Paliesk. ir palaikyk., kad pasirinkt. spart. klav."
"Dukart palieskite ir palaikykite, kad pasirinkt. spartųjį klavišą ar naudotumėte tinkintus veiksmus."
@@ -66,7 +65,12 @@
"Tai sistemos programa ir jos negalima pašalinti."
"Aplankas be pavadinimo"
"„%1$s“ išjungta"
-
+
+ - Programoje „%1$s“ yra %2$d pranešimas
+ - Programoje „%1$s“ yra %2$d pranešimai
+ - Programoje „%1$s“ yra %2$d pranešimo
+ - Programoje „%1$s“ yra %2$d pranešimų
+
"%1$d psl. iš %2$d"
"%1$d pagrindinis ekranas iš %2$d"
"Naujas pagrindinio ekrano puslapis"
@@ -82,17 +86,13 @@
"Išjungė administratorius"
"Leisti pasukti pagrindinį ekraną"
"Kai telefonas pasukamas"
-
-
-
-
-
-
+ "Pranešimų taškai"
+ "Įjungta"
+ "Išjungta"
"Reikalinga prieiga prie pranešimų"
"Kad būtų rodomi pranešimų taškai, įjunkite programos „%1$s“ pranešimus."
"Keisti nustatymus"
-
-
+ "Rodyti pranešimų taškus"
"Pridėti piktogr. prie pagrindinio ekrano"
"Skirta naujoms programoms"
"Pakeisti piktogramos formą"
diff --git a/res/values-lv/strings.xml b/res/values-lv/strings.xml
index 174cda2a63..f9240bd4da 100644
--- a/res/values-lv/strings.xml
+++ b/res/values-lv/strings.xml
@@ -39,8 +39,7 @@
"Notiek lietotņu ielāde…"
"Vaicājumam “%1$s” neatbilda neviena lietotne"
"Meklēt citas lietotnes"
-
-
+ "Lietotne"
"Paziņojumi"
"Lai atlasītu saīsni, pieskarieties un turiet to."
"Lai atlasītu saīsni, veiciet dubultskārienu uz tās un turiet to. Varat arī veikt pielāgotas darbības."
@@ -66,7 +65,11 @@
"Šī ir sistēmas lietotne, un to nevar atinstalēt."
"Mape bez nosaukuma"
"Lietotne %1$s ir atspējota"
-
+
+ - Lietotnē %1$s ir %2$d paziņojumi
+ - Lietotnē %1$s ir %2$d paziņojums
+ - Lietotnē %1$s ir %2$d paziņojumi
+
"%1$d. lapa no %2$d"
"Sākuma ekrāns: %1$d no %2$d"
"Jauna sākuma ekrāna lapa"
@@ -82,17 +85,13 @@
"Atspējojis administrators"
"Atļaut sākuma ekrāna pagriešanu"
"Pagriežot tālruni"
-
-
-
-
-
-
+ "Paziņojumu punkti"
+ "Ieslēgts"
+ "Izslēgts"
"Nepieciešama piekļuve paziņojumiem"
"Lai tiktu rādīti paziņojumu punkti, ieslēdziet paziņojumus lietotnei %1$s."
"Mainīt iestatījumus"
-
-
+ "Rādīt paziņojumu punktus"
"Pievienot ikonu sākuma ekrānā"
"Jaunām lietotnēm"
"Mainīt ikonu formu"
diff --git a/res/values-mk/strings.xml b/res/values-mk/strings.xml
index 4252a78e76..d40b925ebf 100644
--- a/res/values-mk/strings.xml
+++ b/res/values-mk/strings.xml
@@ -39,8 +39,7 @@
"Се вчитуваат апликации…"
"Не се најдени апликации што одговараат на „%1$s“"
"Пребарај други апликации"
-
-
+ "Апликација"
"Известувања"
"Допрете двапати и задржете за избор на кратенка."
"Допрете двапати и задржете за избор на кратенка или користете приспособени дејства."
@@ -66,7 +65,10 @@
"Ова е системска апликација и не може да се деинсталира."
"Неименувана папка"
"%1$s е оневозможена"
-
+
+ - %1$s има %2$d известување
+ - %1$s има %2$d известувања
+
"Страница %1$d од %2$d"
"Екран на почетна страница %1$d од %2$d"
"Нова страница на почетен екран"
@@ -82,17 +84,13 @@
"Оневозможено од администраторот"
"Дозволете ротација на Почетниот екран"
"Кога телефонот се ротира"
-
-
-
-
-
-
+ "Точки за известување"
+ "Вклучено"
+ "Исклучено"
"Потребен е пристап до известувањата"
"За да се прикажуваат „Точки за известување“, вклучете ги известувањата за апликацијата %1$s"
"Промени ги поставките"
-
-
+ "Прикажувај точки за известување"
"Додај икона на почетниот екран"
"За нови апликации"
"Променете ја формата на иконата"
diff --git a/res/values-ml/strings.xml b/res/values-ml/strings.xml
index f34d58c904..93426ad1e0 100644
--- a/res/values-ml/strings.xml
+++ b/res/values-ml/strings.xml
@@ -39,8 +39,7 @@
"ആപ്പുകൾ ലോഡുചെയ്യുന്നു..."
"\"%1$s\" എന്നതുമായി പൊരുത്തപ്പെടുന്ന ആപ്പുകളൊന്നും കണ്ടെത്തിയില്ല"
"കൂടുതൽ ആപ്പുകൾക്ക് തിരയുക"
-
-
+ "ആപ്പ്"
"അറിയിപ്പുകൾ"
"തിരഞ്ഞെടുക്കുന്നതിന് കുറുക്കുവഴി സ്പർശിച്ച് പിടിക്കുക."
"കുറുക്കുവഴി തിരഞ്ഞെടുക്കാനോ ഇഷ്ടാനുസൃത പ്രവർത്തനങ്ങൾ ഉപയോഗിക്കാനോ 2 തവണ ടാപ്പ് ചെയ്ത് പിടിക്കുക."
@@ -66,7 +65,10 @@
"ഇതൊരു സിസ്റ്റം അപ്ലിക്കേഷനായതിനാൽ അൺഇൻസ്റ്റാളുചെയ്യാനാവില്ല."
"പേരുനൽകാത്ത ഫോൾഡർ"
"%1$s പ്രവർത്തനരഹിതമാക്കി"
-
+
+ - %1$s എന്ന ആപ്പിന്, %2$d അറിയിപ്പുകൾ ഉണ്ട്
+ - %1$s എന്ന ആപ്പിന്, %2$d അറിയിപ്പുണ്ട്
+
"പേജ് %1$d / %2$d"
"ഹോം സ്ക്രീൻ %1$d / %2$d"
"പുതിയ ഹോം സ്ക്രീൻ പേജ്"
@@ -82,17 +84,13 @@
"അഡ്മിൻ പ്രവർത്തനരഹിതമാക്കിയിരിക്കുന്നു"
"ഹോം സ്ക്രീൻ തിരിക്കൽ അനുവദിക്കുക"
"ഫോൺ തിരിച്ച നിലയിലായിരിക്കുമ്പോൾ"
-
-
-
-
-
-
+ "അറിയിപ്പ് ഡോട്ടുകൾ"
+ "ഓണാണ്"
+ "ഓഫാണ്"
"അറിയിപ്പിനായുള്ള ആക്സസ് ആവശ്യമാണ്"
"അറിയിപ്പ് ഡോട്ടുകൾ കാണിക്കുന്നതിന്, %1$s എന്നയാളിനായുള്ള ആപ്പ് അറിയിപ്പുകൾ ഓണാക്കുക"
"ക്രമീകരണം മാറ്റുക"
-
-
+ "അറിയിപ്പ് ഡോട്ടുകൾ കാണിക്കുക"
"ഹോം സ്ക്രീനിലേക്ക് ഐക്കൺ ചേർക്കുക"
"പുതിയ ആപ്പുകൾക്ക്"
"ഐക്കണിന്റെ ആകാരം മാറ്റുക"
diff --git a/res/values-mn/strings.xml b/res/values-mn/strings.xml
index e6c9af827f..1b8b3efd8a 100644
--- a/res/values-mn/strings.xml
+++ b/res/values-mn/strings.xml
@@ -39,8 +39,7 @@
"Аппыг ачааллаж байна..."
"\"%1$s\"-д тохирох апп олдсонгүй"
"Бусад апп-г хайх"
-
-
+ "Апп"
"Мэдэгдэл"
"Товчлол авах бол удаан дарна уу."
"Товчлол авах эсвэл тохируулсан үйлдлийг ашиглахын тулд давхар товшоод хүлээнэ үү."
@@ -66,7 +65,10 @@
"Энэ апп нь системийн апп ба устгах боломжгүй."
"Нэргүй фолдер"
"%1$s-г идэвхгүй болгосон"
-
+
+ - %1$s, %2$d мэдэгдэлтэй байна
+ - %1$s, %2$d мэдэгдэлтэй байна
+
"%2$d-н %1$d хуудас"
"%2$d-н Нүүр дэлгэц %1$d"
"Шинэ үндсэн нүүр хуудас"
@@ -82,17 +84,13 @@
"Таны админ идэвхгүй болгосон"
"Нүүр дэлгэцийг эргүүлэхийг зөвшөөрөх"
"Утсыг эргүүлсэн үед"
-
-
-
-
-
-
+ "Мэдэгдлийн цэг"
+ "Асаалттай"
+ "Унтраалттай"
"Мэдэгдлийн хандалт шаардлагатай"
"Мэдэгдлийн цэгийг харуулахын тулд %1$s-д аппын мэдэгдлийг асаана уу"
"Тохиргоог өөрчлөх"
-
-
+ "Мэдэгдлийн цэгийг харуулах"
"Нүүр хуудаст дүрс тэмдэг нэмэх"
"Шинэ аппад зориулсан"
"Дүрс тэмдгийн хэлбэрийг өөрчлөх"
diff --git a/res/values-mr/strings.xml b/res/values-mr/strings.xml
index 022cb7b51c..4f0de654d6 100644
--- a/res/values-mr/strings.xml
+++ b/res/values-mr/strings.xml
@@ -22,8 +22,8 @@
"Launcher3"
"कार्य"
- "अॅप इंस्टॉल केलेला नाही."
- "अॅप उपलब्ध नाही"
+ "अॅप इंस्टॉल केलेला नाही."
+ "अॅप उपलब्ध नाही"
"डाउनलोड केलेला अॅप सुरक्षित मोड मध्ये अक्षम केला"
"विजेट सुरक्षित मोडमध्ये अक्षम झाले"
"शॉर्टकट उपलब्ध नाही"
@@ -39,8 +39,7 @@
"अॅप्स लोड करत आहे…"
"\"%1$s\" शी जुळणारे कोणतेही अॅप्स आढळले नाहीत"
"अधिक अॅप्स शोधा"
-
-
+ "अॅप"
"सूचना"
"शॉर्टकट निवडण्यासाठी स्पर्श करा आणि धरून ठेवा."
"शॉर्टकट निवडण्यासाठी किंवा कस्टम क्रिया वापरण्यासाठी दोनदा टॅप करा आणि धरून ठेवा."
@@ -52,21 +51,24 @@
"होम"
"काढा"
"अनइंस्टॉल करा"
- "अॅप माहिती"
+ "अॅप माहिती"
"इंस्टॉल करा"
"शॉर्टकट स्थापित करा"
- "वापरकर्ता हस्तक्षेपाशिवाय शॉर्टकट जोडण्यास अॅप ला अनुमती देते."
+ "वापरकर्ता हस्तक्षेपाशिवाय शॉर्टकट जोडण्यास अॅप ला अनुमती देते."
"होम सेटिंग्ज आणि शॉर्टकट वाचा"
- "मुख्यपृष्ठातील सेटिंग्ज आणि शॉर्टकट वाचण्यास अॅप ला अनुमती देते."
+ "मुख्यपृष्ठातील सेटिंग्ज आणि शॉर्टकट वाचण्यास अॅप ला अनुमती देते."
"होम सेटिंग्ज आणि शॉर्टकट लिहा"
- "मुख्यपृष्ठातील सेटिंग्ज आणि शॉर्टकट बदलण्यास अॅप ला अनुमती देते."
+ "मुख्यपृष्ठातील सेटिंग्ज आणि शॉर्टकट बदलण्यास अॅप ला अनुमती देते."
"%1$s ला फोन कॉल करण्याची अनुमती नाही"
"विजेट लोड करण्यात समस्या"
"सेटअप"
- "हा सिस्टम अॅप आहे आणि अनइंस्टॉल केला जाऊ शकत नाही."
+ "हा सिस्टम अॅप आहे आणि अनइंस्टॉल केला जाऊ शकत नाही."
"अनामित फोल्डर"
"%1$s अक्षम केला आहे"
-
+
+ - %1$sसाठी%2$dसूचना आहेत
+ - %1$sसाठी %2$d सूचना आहेत
+
"%2$d पैकी %1$d पृष्ठ"
"%2$d पैकी %1$d मुख्य स्क्रीन"
"नवीन मुख्य स्क्रीन पृष्ठ"
@@ -82,17 +84,13 @@
"आपल्या प्रशासकाने अक्षम केले"
"मुख्यस्क्रीन फिरविण्यास अनुमती द्या"
"फोन फिरविला जातो तेव्हा"
-
-
-
-
-
-
+ "सूचना बिंदू"
+ "सुरू"
+ "बंद"
"सूचनांच्या अॅक्सेसची आवश्यकता आहे"
"सूचना बिंदू दाखवण्यासाठी, %1$s साठी अॅप सूचना चालू करा"
"सेटिंग्ज बदला"
-
-
+ "सूचना बिंदू दाखवा"
"होम स्क्रीनवर आयकन जोडा"
"नवीन अॅप्ससाठी"
"चिन्हाचा आकार बदला"
@@ -106,8 +104,8 @@
"अज्ञात"
"काढा"
"शोधा"
- "हा अॅप इंस्टॉल केलेला नाही"
- "या चिन्हासाठी अॅप इंस्टॉल केलेला नाही. तुम्ही ते काढू शकता किंवा अॅपचा शोध घेऊ शकता आणि त्यास व्यक्तिचलितपणे इंस्टॉल करू शकता."
+ "हा अॅप इंस्टॉल केलेला नाही"
+ "या चिन्हासाठी अॅप इंस्टॉल केलेला नाही. तुम्ही ते काढू शकता किंवा अॅपचा शोध घेऊ शकता आणि त्यास व्यक्तिचलितपणे इंस्टॉल करू शकता."
"%1$s डाउनलोड होत आहे , %2$s पूर्ण झाले"
"%1$s इंस्टॉल करण्याची प्रतिक्षा करत आहे"
"%1$s विजेट"
diff --git a/res/values-ms/strings.xml b/res/values-ms/strings.xml
index e30d632687..4654209c1a 100644
--- a/res/values-ms/strings.xml
+++ b/res/values-ms/strings.xml
@@ -39,8 +39,7 @@
"Memuatkan apl…"
"Tiada apl yang ditemui sepadan dengan \"%1$s\""
"Cari lagi apl"
-
-
+ "Apl"
"Pemberitahuan"
"Sentuh & tahan untuk mengambil pintasan."
"Ketik dua kali & tahan untuk mengambil pintasan atau menggunakan tindakan tersuai."
@@ -66,7 +65,10 @@
"Ini ialah apl sistem dan tidak boleh dinyahpasang."
"Folder Tanpa Nama"
"%1$s dilumpuhkan"
-
+
+ - %1$s, mempunyai %2$d pemberitahuan
+ - %1$s, mempunyai %2$d pemberitahuan
+
"Halaman %1$d daripada %2$d"
"Skrin Laman Utama %1$d daripada %2$d"
"Halaman skrin utama baharu"
@@ -82,17 +84,13 @@
"Dilumpuhkan oleh pentadbir anda"
"Benarkan putaran Skrin Utama"
"Apabila telefon diputar"
-
-
-
-
-
-
+ "Titik pemberitahuan"
+ "Hidup"
+ "Mati"
"Akses pemberitahuan diperlukan"
"Untuk menunjukkan Titik Pemberitahuan, hidupkan pemberitahuan apl untuk %1$s"
"Tukar tetapan"
-
-
+ "Tunjukkan titik pemberitahuan"
"Tambahkan ikon pada Skrin Utama"
"Untuk apl baharu"
"Tukar bentuk ikon"
diff --git a/res/values-my/strings.xml b/res/values-my/strings.xml
index 06598e06fb..f25de749f2 100644
--- a/res/values-my/strings.xml
+++ b/res/values-my/strings.xml
@@ -39,8 +39,7 @@
"အက်ပ်များကို ဖွင့်နေသည်…"
"\"%1$s\" နှင့်ကိုက်ညီသည့် အပ်ပ်များကို မတွေ့ပါ"
"နောက်ထပ် အက်ပ်များကို ရှာပါ"
-
-
+ "အက်ပ်"
"အကြောင်းကြားချက်များ"
"ဖြတ်လမ်းလင့်ခ်တစ်ခုကို ရွေးရန် ထိပြီး ဖိထားပါ။"
"ဖြတ်လမ်းလင့်ခ်ကို ရွေးရန် (သို့) စိတ်ကြိုက်လုပ်ဆောင်ချက်များကို သုံးရန် နှစ်ချက်တို့ပြီး ဖိထားပါ။"
@@ -66,7 +65,10 @@
"ဤအပ်ပလီကေးရှင်းမှာ စစ်စတန်ပိုင်းဆိုင်ရာ အပ်ပလီကေးရှင်းဖြစ်ပါသည်။ ထုတ်ပစ်၍ မရပါ"
"အမည်မရှိအကန့်"
"%1$s ကို ပိတ်ထားသည်"
-
+
+ - %1$s တွင် သတိပေးချက် %2$d ခု ရှိသည်
+ - %1$s တွင် သတိပေးချက် %2$d ခု ရှိသည်
+
"စာမျက်နှာ %1$d မှ %2$d"
"ပင်မစာမျက်နှာ %1$d မှ %2$d"
"ပင်မမျက်နှာပြင် စာမျက်နှာသစ်"
@@ -82,17 +84,13 @@
"သင့်စီမံခန့်ခွဲသူက ပိတ်လိုက်ပါသည်"
"ပင်မစာမျက်နှာလှည့်ခြင်းကို ခွင့်ပြုပါ"
"ဖုန်းကိုလှည့်ထားစဉ်"
-
-
-
-
-
-
+ "သတိပေးချက် အစက်များ"
+ "ဖွင့်ထားသည်"
+ "ပိတ်ထားသည်"
"အကြောင်းကြားချက် အသုံးပြုခွင့် လိုအပ်သည်"
"အကြောင်းကြားချက် အစက်များကို ပြသရန် %1$s အတွက် အက်ပ်အကြောင်းကြားချက်များကို ဖွင့်ပါ"
"ဆက်တင်များ ပြောင်းရန်"
-
-
+ "သတိပေးချက် အစက်များ ပြရန်"
"ပင်မစာမျက်နှာသို့ သင်္ကေတပုံ ထည့်ရန်"
"အက်ပ်အသစ်များအတွက်"
"သင်္ကေတပုံစံကို ပြောင်းရန်"
diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml
index 6534f85fbc..7400beb62d 100644
--- a/res/values-nb/strings.xml
+++ b/res/values-nb/strings.xml
@@ -39,8 +39,7 @@
"Laster inn appene …"
"Fant ingen apper som samsvarer med «%1$s»"
"Søk etter flere apper"
-
-
+ "App"
"Varsler"
"Trykk og hold for å velge en snarvei."
"Dobbelttrykk og hold for å velge en snarvei eller bruke tilpassede handlinger."
@@ -66,7 +65,10 @@
"Dette er en systemapp som ikke kan avinstalleres."
"Mappe uten navn"
"Slo av %1$s"
-
+
+ - %1$s har %2$d varsler
+ - %1$s har %2$d varsel
+
"Side %1$d av %2$d"
"Startside %1$d av %2$d"
"Ny side på startskjermen"
@@ -82,17 +84,13 @@
"Administratoren har slått av funksjonen"
"Tillat rotasjon av startskjermen"
"Når telefonen roteres"
-
-
-
-
-
-
+ "Varselsprikker"
+ "På"
+ "Av"
"Tilgang til varsler er nødvendig"
"Slå på appvarsler for %1$s for å vise varselsprikker"
"Endre innstillingene"
-
-
+ "Vis varselsprikker"
"Legg til ikon på startsiden"
"For nye apper"
"Endre formen på ikonet"
diff --git a/res/values-ne/strings.xml b/res/values-ne/strings.xml
index d205109d7b..be40ec162d 100644
--- a/res/values-ne/strings.xml
+++ b/res/values-ne/strings.xml
@@ -39,8 +39,7 @@
"अनुप्रयोगहरू लोड गर्दै…"
"\"%1$s\" सँग मिल्दो कुनै अनुप्रयोग भेटिएन"
"थप अनुप्रयोगहरू खोज्नुहोस्"
-
-
+ "अनुप्रयोग"
"सूचनाहरू"
"कुनै सर्टकट छनौट गर्न छोइराख्नुहोस्।"
"कुनै सर्टकट छनौट गर्न वा रोजेका कारबाहीहरू प्रयोग गर्न डबल ट्याप गरेर छोइराख्नुहोस्।"
@@ -66,7 +65,10 @@
"यो प्रणाली अनुप्रयोग हो र यसलाई स्थापना रद्द गर्न सकिँदैन।"
"बेनाम फोल्डर"
"असक्षम पारिएको %1$s"
-
+
+ - %1$s, का %2$d सूचनाहरू छन्
+ - %1$s, को %2$d सूचना छ
+
"पृष्ठ %2$d को %1$d"
"गृह स्क्रिन %1$d को %2$d"
"नयाँ गृह स्क्रिन पृष्ठ"
@@ -82,17 +84,13 @@
"तपाईँको प्रशासकद्वारा असक्षम गरिएको"
"गृह स्क्रिनलाई घुम्ने अनुमति दिनुहोस्"
"फोनलाई घुमाइँदा"
-
-
-
-
-
-
+ "सूचनाको प्रतीक जनाउने थोप्लाहरू"
+ "सक्रिय"
+ "निष्क्रिय"
"सूचनासम्बन्धी पहुँच आवश्यक हुन्छ"
"सूचनाको प्रतीक जनाउने थोप्लाहरू देखाउन %1$s को अनुप्रयोगसम्बन्धी सूचनाहरूलाई सक्रिय गर्नुहोस्"
"सेटिङहरू बदल्नुहोस्"
-
-
+ "सूचनाको प्रतीक जनाउने थोप्लाहरू देखाउनुहोस्"
"गृह स्क्रिनमा आइकन थप्नुहोस्"
"नयाँ अनुप्रयोगका लागि"
"आइकनको आकार परिवर्तन गर्नुहोस्"
diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml
index e4b22332a5..b0e0cb23ce 100644
--- a/res/values-nl/strings.xml
+++ b/res/values-nl/strings.xml
@@ -39,8 +39,7 @@
"Apps laden…"
"Er zijn geen apps gevonden die overeenkomen met \'%1$s\'"
"Zoeken naar meer apps"
-
-
+ "App"
"Meldingen"
"Tik en houd vast om snelkoppeling toe te voegen."
"Dubbeltik en houd vast om een snelkoppeling toe te voegen of aangepaste acties te gebruiken."
@@ -66,7 +65,10 @@
"Dit is een systeemapp die niet kan worden verwijderd."
"Naamloze map"
"%1$s is uitgeschakeld"
-
+
+ - %1$s, heeft %2$d meldingen
+ - %1$s, heeft %2$d melding
+
"Pagina %1$d van %2$d"
"Startscherm %1$d van %2$d"
"Nieuwe startschermpagina"
@@ -82,17 +84,13 @@
"Uitgeschakeld door je beheerder"
"Draaien van startscherm toestaan"
"Wanneer de telefoon gedraaid is"
-
-
-
-
-
-
+ "Meldingsstipjes"
+ "Aan"
+ "Uit"
"Toegang tot meldingen vereist"
"Als je meldingsstipjes wilt weergeven, schakel je app-meldingen in voor %1$s"
"Instellingen wijzigen"
-
-
+ "Meldingsstipjes weergeven"
"Pictogram toevoegen aan startscherm"
"Voor nieuwe apps"
"Vorm van pictogram wijzigen"
diff --git a/res/values-or/strings.xml b/res/values-or/strings.xml
index e4351c18c7..8c2632529c 100644
--- a/res/values-or/strings.xml
+++ b/res/values-or/strings.xml
@@ -39,8 +39,7 @@
"ଆପ୍ ଲୋଡ୍ ହେଉଛି..."
"\"%1$s\" ସହିତ ମେଳ ହେଉଥିବା କୌଣସି ଆପ୍ ମିଳିଲା ନାହିଁ"
"ଅଧିକ ଆପ୍ ଖୋଜନ୍ତୁ"
-
-
+ "ଆପ୍"
"ବିଜ୍ଞପ୍ତି"
"ଏକ ଶର୍ଟକଟ୍ ଚୟନ କରିବାକୁ ସ୍ପର୍ଶ କରି ଧରି ରଖନ୍ତୁ।"
"ଡବଲ୍-ଟାପ୍ କରନ୍ତୁ ଏବଂ ଏକ ଶର୍ଟକଟ୍ ଚୟନ କରିବାକୁ ଧରି ରଖନ୍ତୁ କିମ୍ୱା କଷ୍ଟମ୍ ପ୍ରକ୍ରିୟା ବ୍ୟବହାର କରନ୍ତୁ।"
@@ -66,7 +65,10 @@
"ଏହା ଏକ ସିଷ୍ଟମ୍ ଆପ୍ ଅଟେ ଏବଂ ଏହା ଅନଇନଷ୍ଟଲ୍ କରାଯାଇ ପାରିବ ନାହିଁ।"
"ବେନାମୀ ଫୋଲ୍ଡର୍"
"%1$s ଅକ୍ଷମ କରାଗଲା"
-
+
+ - %1$s, %2$dଟି ବିଜ୍ଞପ୍ତି ରହିଛି
+ - %1$s, %2$dଟି ବିଜ୍ଞପ୍ତି ରହିଛି
+
"ମୋଟ %2$dରୁ %1$d ନମ୍ବର ପୃଷ୍ଠା"
"%2$dରୁ %1$d ହୋମ୍ ସ୍କ୍ରୀନ୍"
"ନୂଆ ହୋମ୍ ସ୍କ୍ରୀନ୍ ପୃଷ୍ଠା"
@@ -82,17 +84,13 @@
"ଆପଣଙ୍କ ଆଡମିନଙ୍କ ଦ୍ୱାରା ଅକ୍ଷମ କରାଯାଇଛି"
"ହୋମ୍ ସ୍କ୍ରୀନ୍ ବୁଲାଇବା ଅନୁମତି ଦିଅନ୍ତୁ"
"ଯେତେବେଳେ ଫୋନକୁ ବୁଲାଯାଇଥାଏ"
-
-
-
-
-
-
+ "ବିଜ୍ଞପ୍ତି ବିନ୍ଦୁଗୁଡ଼ିକ"
+ "ଚାଲୁ କରନ୍ତୁ"
+ "ବନ୍ଦ କରନ୍ତୁ"
"ବିଜ୍ଞପ୍ତି ଆକ୍ସେସ୍ ଆବଶ୍ୟକ ଅଟେ"
"ବିଜ୍ଞପ୍ତି ବିନ୍ଦୁ ଦେଖାଇବାକୁ, %1$s ପାଇଁ ଆପ୍ ବିଜ୍ଞପ୍ତି ଅନ୍ କରନ୍ତୁ"
"ସେଟିଙ୍ଗ ପରିବର୍ତ୍ତନ କରନ୍ତୁ"
-
-
+ "ବିଜ୍ଞପ୍ତି ଡଟ୍ଗୁଡ଼ିକୁ ଦେଖାନ୍ତୁ"
"ହୋମ୍ ସ୍କ୍ରୀନରେ ଆଇକନ୍କୁ ଯୋଡ଼ନ୍ତୁ"
"ନୂଆ ଆପ୍ ପାଇଁ"
"ଆଇକନ୍ର ଆକାର ପରିବର୍ତ୍ତନ କରନ୍ତୁ"
diff --git a/res/values-pa/strings.xml b/res/values-pa/strings.xml
index ba75e1e205..f21fc0df16 100644
--- a/res/values-pa/strings.xml
+++ b/res/values-pa/strings.xml
@@ -39,8 +39,7 @@
"ਐਪਾਂ ਨੂੰ ਲੋਡ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ..."
"\"%1$s\" ਨਾਲ ਮੇਲ ਖਾਂਦੀਆਂ ਕੋਈ ਐਪਾਂ ਨਹੀਂ ਮਿਲੀਆਂ"
"ਹੋਰ ਐਪਾਂ ਖੋਜੋ"
-
-
+ "ਐਪ"
"ਸੂਚਨਾਵਾਂ"
"ਕੋਈ ਸ਼ਾਰਟਕੱਟ ਚੁਣਨ ਲਈ ਸਪੱਰਸ਼ ਕਰਕੇ ਦਬਾਈ ਰੱਖੋ।"
"ਕੋਈ ਸ਼ਾਰਟਕੱਟ ਚੁਣਨ ਲਈ ਡਬਲ ਟੈਪ ਕਰਕੇ ਦਬਾਈ ਰੱਖੋ ਜਾਂ ਵਿਉਂਤੀਆਂ ਕਾਰਵਾਈਆਂ ਵਰਤੋ।"
@@ -66,7 +65,10 @@
"ਇਹ ਇੱਕ ਸਿਸਟਮ ਐਪ ਹੈ ਅਤੇ ਇਸਨੂੰ ਅਣਇੰਸਟੌਲ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ।"
"ਬਿਨਾਂ ਨਾਮ ਦਿੱਤਾ ਫੋਲਡਰ"
"%1$s ਨੂੰ ਅਯੋਗ ਬਣਾਇਆ ਗਿਆ"
-
+
+ - %1$s ਦੀ %2$d ਸੂਚਨਾ
+ - %1$s ਦੀਆਂ %2$d ਸੂਚਨਾਵਾਂ
+
"ਸਫ਼ਾ %2$d ਦਾ %1$d"
"ਹੋਮ ਸਕ੍ਰੀਨ %2$d ਦੀ %1$d"
"ਨਵਾਂ ਹੋਮ ਸਕ੍ਰੀਨ ਸਫ਼ਾ"
@@ -82,17 +84,13 @@
"ਤੁਹਾਡੇ ਪ੍ਰਸ਼ਾਸਕ ਦੁਆਰਾ ਅਯੋਗ ਬਣਾਈ ਗਈ"
"ਹੋਮ ਸਕ੍ਰੀਨ ਨੂੰ ਘੁੰਮਾਉਣ ਦੀ ਆਗਿਆ ਦਿਓ"
"ਜਦੋਂ ਫ਼ੋਨ ਘੁੰਮਾਇਆ ਜਾਂਦਾ ਹੈ"
-
-
-
-
-
-
+ "ਸੂਚਨਾ ਬਿੰਦੂ"
+ "ਚਾਲੂ"
+ "ਬੰਦ"
"ਸੂਚਨਾ ਪਹੁੰਚ ਲੋੜੀਂਦੀ ਹੈ"
"ਸੂਚਨਾ ਬਿੰਦੂਆਂ ਦਿਖਾਉਣ ਲਈ, %1$s ਲਈ ਐਪ ਸੂਚਨਾਵਾਂ ਚਾਲੂ ਕਰੋ"
"ਸੈਟਿੰਗਾਂ ਬਦਲੋ"
-
-
+ "ਸੂਚਨਾ ਬਿੰਦੂ ਦਿਖਾਓ"
"ਹੋਮ ਸਕ੍ਰੀਨ \'ਤੇ ਪ੍ਰਤੀਕ ਸ਼ਾਮਲ ਕਰੋ"
"ਨਵੀਆਂ ਐਪਾਂ ਲਈ"
"ਪ੍ਰਤੀਕ ਦੀ ਆਕ੍ਰਿਤੀ ਬਦਲੋ"
diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml
index a4a6e98379..242d00dd39 100644
--- a/res/values-pl/strings.xml
+++ b/res/values-pl/strings.xml
@@ -39,8 +39,7 @@
"Ładuję aplikacje…"
"Nie znaleziono aplikacji pasujących do zapytania „%1$s”"
"Wyszukaj więcej aplikacji"
-
-
+ "Aplikacja"
"Powiadomienia"
"Kliknij i przytrzymaj, by wybrać skrót."
"Kliknij dwukrotnie i przytrzymaj, by wybrać skrót lub użyć działań niestandardowych."
@@ -66,7 +65,12 @@
"To aplikacja systemowa i nie można jej odinstalować."
"Folder bez nazwy"
"Aplikacja %1$s jest wyłączona"
-
+
+ - %1$s – %2$d powiadomienia
+ - %1$s – %2$d powiadomień
+ - %1$s – %2$d powiadomienia
+ - %1$s – %2$d powiadomienie
+
"Strona %1$d z %2$d"
"Ekran główny %1$d z %2$d"
"Nowa strona ekranu głównego"
@@ -82,17 +86,13 @@
"Funkcja wyłączona przez administratora"
"Zezwalaj na obrót ekranu głównego"
"Po obróceniu telefonu"
-
-
-
-
-
-
+ "Plakietki z powiadomieniami"
+ "Włączono"
+ "Wyłączono"
"Wymagany jest dostęp do powiadomień"
"Aby pokazać plakietki z powiadomieniami, włącz powiadomienia aplikacji %1$s"
"Zmień ustawienia"
-
-
+ "Pokaż plakietki z powiadomieniami"
"Dodaj ikonę do ekranu głównego"
"W przypadku nowych aplikacji"
"Zmień kształt ikon"
diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml
index 39bd520fcc..1e89abe4b7 100644
--- a/res/values-pt/strings.xml
+++ b/res/values-pt/strings.xml
@@ -39,8 +39,7 @@
"Carregando apps…"
"Nenhum app encontrado que corresponda a \"%1$s\""
"Pesquisar mais apps"
-
-
+ "App"
"Notificações"
"Toque e segure para selecionar um atalho."
"Toque duas vezes na tela e segure para selecionar um atalho ou usar ações personalizadas."
@@ -66,7 +65,10 @@
"Este é um app do sistema e não pode ser desinstalado."
"Pasta sem nome"
"%1$s desativado"
-
+
+ - O app %1$stem %2$d notificação
+ - O app %1$stem %2$d notificações
+
"Página %1$d de %2$d"
"Tela inicial %1$d de %2$d"
"Nova página na tela inicial"
@@ -82,17 +84,13 @@
"Desativado pelo administrador"
"Permitir rotação da tela inicial"
"Quando o smartphone for girado"
-
-
-
-
-
-
+ "Pontos de notificação"
+ "Ativado"
+ "Desativado"
"Acesso a notificações necessário"
"Para mostrar pontos de notificação, ative as notificações de app para %1$s"
"Alterar configurações"
-
-
+ "Mostrar pontos de notificação"
"Adicionar ícone à tela inicial"
"Para novos apps"
"Alterar forma de ícones"
diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml
index c66016af4b..7135f62cca 100644
--- a/res/values-ro/strings.xml
+++ b/res/values-ro/strings.xml
@@ -39,8 +39,7 @@
"Se încarcă aplicații…"
"Nu s-a găsit nicio aplicație pentru „%1$s\""
"Căutați mai multe aplicații"
-
-
+ "Aplicație"
"Notificări"
"Atingeți lung pentru a selecta o comandă rapidă."
"Atingeți lung pentru a selecta o comandă rapidă sau folosiți acțiuni personalizate."
@@ -66,7 +65,11 @@
"Aceasta este o aplicație de sistem și nu poate fi dezinstalată."
"Dosar fără nume"
"S-a dezactivat %1$s"
-
+
+ - %1$s are %2$d notificări
+ - %1$s are %2$d de notificări
+ - %1$s are %2$d notificare
+
"Pagina %1$d din %2$d"
"Ecranul de pornire %1$d din %2$d"
"Pagină nouă pe ecranul de pornire"
@@ -82,17 +85,13 @@
"Dezactivată de administrator"
"Permiteți rotirea ecranului de pornire"
"Când telefonul este rotit"
-
-
-
-
-
-
+ "Puncte de notificare"
+ "Activate"
+ "Dezactivate"
"Este necesar accesul la notificări"
"Pentru a afișa punctele de notificare, activați notificările din aplicație pentru %1$s"
"Modificați setările"
-
-
+ "Afișați punctele de notificare"
"Adaugă pictograme în ecranul de pornire"
"Pentru aplicații noi"
"Schimbați forma pictogramei"
diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml
index 7e73dd6e16..b4d1664f9d 100644
--- a/res/values-ru/strings.xml
+++ b/res/values-ru/strings.xml
@@ -39,8 +39,7 @@
"Загрузка приложений…"
"По запросу \"%1$s\" ничего не найдено"
"Искать другие приложения"
-
-
+ "Приложение"
"Уведомления"
"Нажмите и удерживайте, чтобы выбрать ярлык."
"Нажмите дважды и удерживайте, чтобы выбрать ярлык или использовать специальные действия."
@@ -66,7 +65,12 @@
"Это системное приложение, его нельзя удалить."
"Папка без названия"
"Приложение %1$s отключено"
-
+
+ - В приложении \"%1$s\" %2$d уведомление
+ - В приложении \"%1$s\" %2$d уведомления
+ - В приложении \"%1$s\" %2$d уведомлений
+ - В приложении \"%1$s\" %2$d уведомления
+
"Стр. %1$d из %2$d"
"Главный экран %1$d из %2$d"
"Новый экран"
@@ -82,17 +86,13 @@
"Функция отключена администратором"
"Разрешить поворачивать главный экран"
"Когда телефон повернут"
-
-
-
-
-
-
+ "Значки уведомлений"
+ "Включены"
+ "Отключены"
"Нет доступа к уведомлениям"
"Чтобы показывать значки уведомлений, включите уведомления в приложении \"%1$s\""
"Изменить настройки"
-
-
+ "Показывать значки уведомлений"
"Добавлять значки"
"Добавлять значки установленных приложений на главный экран"
"Изменить форму значков"
diff --git a/res/values-si/strings.xml b/res/values-si/strings.xml
index b175f890bb..af428a9ed7 100644
--- a/res/values-si/strings.xml
+++ b/res/values-si/strings.xml
@@ -39,8 +39,7 @@
"යෙදුම් පූරණය වෙමින්…"
"\"%1$s\" සමග ගැළපෙන යෙදුම් හමු නොවිණි"
"තව යෙදුම් සඳහා සොයන්න"
-
-
+ "යෙදුම"
"දැනුම්දීම්"
"කෙටි මගක් තෝරා ගැනීමට ස්පර්ශ කර අල්ලාගෙන සිටින්න."
"විජට් එකක් තෝරා ගැනීමට හෝ අභිරුචි භාවිත කිරීමට දෙවරක් තට්ටු කර අල්ලා ගෙන සිටින්න."
@@ -66,7 +65,10 @@
"මෙය පද්ධති යෙදුමක් වන අතර අස්ථාපනය කළ නොහැක."
"නම් නොකළ ෆෝල්ඩරය"
"%1$s අබල කෙරිණි"
-
+
+ - %1$s, දැනුම්දීම් %2$dක් ඇත
+ - %1$s, දැනුම්දීම් %2$dක් ඇත
+
"%2$d හි %1$d පිටුව"
"මුල් පිටු තිරය %2$d හි %1$d"
"නව මුල් පිටුව"
@@ -82,17 +84,13 @@
"ඔබගේ පරිපාලක විසින් අබල කරන ලදී"
"මුල් පිටු තිරය කරකැවීමට ඉඩ දෙන්න"
"දුරකථනය කරකවන විට"
-
-
-
-
-
-
+ "දැනුම්දීම් තිත්"
+ "ක්රියාත්මකයි"
+ "ක්රියාවිරහිතයි"
"දැනුම්දීම් ප්රවේශය අවශ්යයි"
"දැනුම්දීම් තිත් පෙන්වීමට, %1$s සඳහා යෙදුම් දැනුම්දීම් සබල කරන්න"
"සැකසීම් වෙනස් කරන්න"
-
-
+ "දැනුම්දීම් තිත් පෙන්වන්න"
"මුල් පිටු තිරය වෙත අයිකනය එක් කරන්න"
"නව යෙදුම් සඳහා"
"නිරූපක හැඩය වෙනස් කරන්න"
diff --git a/res/values-sk/strings.xml b/res/values-sk/strings.xml
index af66bf731f..b7014b2212 100644
--- a/res/values-sk/strings.xml
+++ b/res/values-sk/strings.xml
@@ -39,8 +39,7 @@
"Načítavajú sa aplikácie…"
"Nenašli sa žiadne aplikácie zodpovedajúce dopytu %1$s"
"Hľadať ďalšie aplikácie"
-
-
+ "Aplikácia"
"Upozornenia"
"Skratku pridáte pridržaním."
"Skratku pridáte dvojitým klepnutím a pridržaním alebo pomocou vlastných akcií."
@@ -66,7 +65,12 @@
"Toto je systémová aplikácia a nedá sa odinštalovať."
"Nepomenovaný priečinok"
"Aplikácia %1$s je deaktivovaná"
-
+
+ - %1$s, má %2$d upozornenia
+ - %1$s, has %2$d notifications
+ - %1$s, má %2$d upozornení
+ - %1$s, má %2$d upozornenie
+
"Stránka %1$d z %2$d"
"Plocha %1$d z %2$d"
"Nová stránka plochy"
@@ -82,17 +86,13 @@
"Zakázané vaším správcom"
"Povoliť otáčanie plochy"
"Pri otočení telefónu"
-
-
-
-
-
-
+ "Bodky upozornení"
+ "Zapnuté"
+ "Vypnuté"
"Vyžaduje sa prístup k upozorneniam"
"Ak chcete, aby sa zobrazovali bodky upozornení, zapnite upozornenia aplikácie %1$s"
"Zmeniť nastavenia"
-
-
+ "Zobrazovať bodky upozornení"
"Pridať ikonu na plochu"
"Pri inštalácii novej aplikácie"
"Zmeniť tvar ikony"
diff --git a/res/values-sl/strings.xml b/res/values-sl/strings.xml
index 4f5fc1214d..891fd1f906 100644
--- a/res/values-sl/strings.xml
+++ b/res/values-sl/strings.xml
@@ -39,8 +39,7 @@
"Nalaganje aplikacij …"
"Ni aplikacij, ki bi ustrezale poizvedbi »%1$s«"
"Iskanje več aplikacij"
-
-
+ "Aplikacija"
"Obvestila"
"Pridržite bližnjico, da jo izberete."
"Dvakrat se dotaknite bližnjice in jo pridržite, da jo izberete, ali pa uporabite dejanja po meri."
@@ -66,7 +65,12 @@
"To je sistemska aplikacija in je ni mogoče odstraniti."
"Neimenovana mapa"
"Aplikacija %1$s je onemogočena"
-
+
+ - %1$s ima %2$d obvestilo
+ - %1$s ima %2$d obvestili
+ - %1$s ima %2$d obvestila
+ - %1$s ima %2$d obvestil
+
"Stran %1$d od %2$d"
"Začetni zaslon %1$d od %2$d"
"Nova stran na začetnem zaslonu"
@@ -82,17 +86,13 @@
"Onemogočil skrbnik."
"Omogočanje sukanja začetnega zaslona"
"Ko se telefon zasuka"
-
-
-
-
-
-
+ "Obvestilne pike"
+ "Vklopljeno"
+ "Izklopljeno"
"Potreben je dostop do obvestil"
"Za prikaz obvestilnih pik vklopite obvestila aplikacije %1$s"
"Spremeni nastavitve"
-
-
+ "Pokaži obvestilne pike"
"Dodaj ikono na začetni zaslon"
"Za nove aplikacije"
"Spremeni obliko ikon"
diff --git a/res/values-sq/strings.xml b/res/values-sq/strings.xml
index ad53e119c0..dd657d7f26 100644
--- a/res/values-sq/strings.xml
+++ b/res/values-sq/strings.xml
@@ -39,8 +39,7 @@
"Po ngarkon aplikacionet..."
"Nuk u gjet asnjë aplikacion që përputhet me \"%1$s\""
"Kërko për më shumë aplikacione"
-
-
+ "Aplikacioni"
"Njoftimet"
"Prek dhe mbaj prekur për të zgjedhur një shkurtore."
"Prek dy herë dhe mbaj prekur për të zgjedhur një shkurtore ose për të përdorur veprimet e personalizuara."
@@ -66,7 +65,10 @@
"Ky është aplikacion sistemi dhe nuk mund të çinstalohet."
"Dosje e paemërtuar"
"%1$s u çaktivizua"
-
+
+ - %1$s, ka %2$d njoftime
+ - %1$s, ka %2$d njoftim
+
"Faqja: %1$d nga gjithsej %2$d"
"Ekrani bazë: %1$d nga gjithsej %2$d"
"Faqja e ekranit të ri kryesor"
@@ -82,17 +84,13 @@
"Çaktivizuar nga administratori"
"Lejo rrotullimin e ekranit kryesor"
"Kur telefoni rrotullohet"
-
-
-
-
-
-
+ "Pikat e njoftimeve"
+ "Aktiv"
+ "Joaktiv"
"Nevojitet qasja në njoftime"
"Për të shfaqur \"Pikat e njoftimeve\", aktivizo njoftimet e aplikacionit për %1$s"
"Ndrysho cilësimet"
-
-
+ "Shfaq pikat e njoftimeve"
"Shto ikonë në ekranin bazë"
"Për aplikacionet e reja"
"Ndrysho formën e ikonës"
diff --git a/res/values-sr/strings.xml b/res/values-sr/strings.xml
index d68696a941..c16d32f26f 100644
--- a/res/values-sr/strings.xml
+++ b/res/values-sr/strings.xml
@@ -39,8 +39,7 @@
"Апликације се учитавају…"
"Није пронађена ниједна апликација за „%1$s“"
"Претражи још апликација"
-
-
+ "Апликација"
"Обавештења"
"Додирните и задржите да бисте изабрали пречицу."
"Двапут додирните и задржите да бисте изабрали пречицу или користите прилагођене радње."
@@ -66,7 +65,11 @@
"Ово је системска апликација и не може да се деинсталира."
"Неименовани директоријум"
"Апликација %1$s је онемогућена"
-
+
+ - %1$s, има %2$d обавештење
+ - %1$s, има %2$d обавештења
+ - %1$s, има %2$d обавештења
+
"%1$d. страница од %2$d"
"%1$d. почетни екран од %2$d"
"Нова страница почетног екрана"
@@ -82,17 +85,13 @@
"Администратор је онемогућио"
"Дозволи ротацију почетног екрана"
"Када се телефон ротира"
-
-
-
-
-
-
+ "Тачке за обавештења"
+ "Укључено"
+ "Искључено"
"Потребан је приступ за обавештења"
"Да бисте приказали тачке за обавештења, укључите обавештења за апликацију %1$s"
"Промените подешавања"
-
-
+ "Приказуј тачке за обавештења"
"Додај икону на почетни екран"
"За нове апликације"
"Промените облик икона"
diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml
index 7c4f41f035..feb087c91a 100644
--- a/res/values-sv/strings.xml
+++ b/res/values-sv/strings.xml
@@ -39,8 +39,7 @@
"Läser in appar …"
"Inga appar som matchar %1$s hittades"
"Sök efter fler appar"
-
-
+ "App"
"Aviseringar"
"Tryck länge om du vill ta upp en genväg."
"Tryck snabbt två gånger och håll kvar om du vill ta upp en genväg eller använda anpassade åtgärder."
@@ -66,7 +65,10 @@
"Det här är en systemapp som inte kan avinstalleras."
"Namnlös mapp"
"%1$s har inaktiverats"
-
+
+ - %1$s har %2$d aviseringar
+ - %1$s har %2$d avisering
+
"Sidan %1$d av %2$d"
"Startskärmen %1$d av %2$d"
"Ny sida på startskärmen"
@@ -82,17 +84,13 @@
"Inaktiverat av administratören"
"Tillåt rotering av startskärmen"
"När mobilen vrids"
-
-
-
-
-
-
+ "Aviseringsprickar"
+ "På"
+ "Av"
"Åtkomst till aviseringar krävs"
"Aktivera appaviseringar för %1$s om du vill att aviseringsprickar ska visas"
"Ändra inställningar"
-
-
+ "Visa aviseringsprickar"
"Lägg till ikonen på startskärmen"
"För nya appar"
"Ändra form på ikoner"
diff --git a/res/values-sw/strings.xml b/res/values-sw/strings.xml
index b6bdbd3fb7..99d3008914 100644
--- a/res/values-sw/strings.xml
+++ b/res/values-sw/strings.xml
@@ -39,8 +39,7 @@
"Inapakia programu..."
"Haikupata programu zozote zinazolingana na \"%1$s\""
"Tafuta programu zaidi"
-
-
+ "Programu"
"Arifa"
"Gusa na ushikilie ili uchague njia ya mkato."
"Gusa mara mbili na ushikilie ili uchague njia ya mkato au utumie vitendo maalum."
@@ -66,7 +65,10 @@
"Hii ni programu ya mfumo na haiwezi kuondolewa."
"Folda isiyo na jina"
"%1$s imezimwa"
-
+
+ - %1$s, ina arifa %2$d
+ - %1$s, ina arifa %2$d
+
"Ukurasa%1$d wa %2$d"
@@ -84,17 +86,13 @@
"Imezimwa na msimamizi wako"
"Ruhusu kuzungusha skrini ya Kwanza"
"Simu inapozungushwa"
-
-
-
-
-
-
+ "Vitone vya arifa"
+ "Imewashwa"
+ "Imezimwa"
"Inahitaji idhini ya kufikia arifa"
"Ili kuonyesha Vitone vya Arifa, washa kipengele cha arifa za programu katika %1$s"
"Badilisha mipangilio"
-
-
+ "Onyesha vitone vya arifa"
"Ongeza aikoni kwenye Skrini ya kwanza"
"Kwa ajili ya programu mpya"
"Badilisha umbo la aikoni"
diff --git a/res/values-ta/strings.xml b/res/values-ta/strings.xml
index b25d1d21a3..43ff0977cd 100644
--- a/res/values-ta/strings.xml
+++ b/res/values-ta/strings.xml
@@ -39,8 +39,7 @@
"பயன்பாடுகளை ஏற்றுகிறது…"
"\"%1$s\" உடன் பொருந்தும் பயன்பாடுகள் இல்லை"
"கூடுதல் பயன்பாடுகளைத் தேடு"
-
-
+ "ஆப்ஸ்"
"அறிவிப்புகள்"
"ஷார்ட்கட்டைச் சேர்க்க, தொட்டு பிடித்திருக்கவும்."
"ஷார்ட்கட்டைச் சேர்க்க, இருமுறை தட்டிப் பிடித்திருக்கவும் (அ) தனிப்பயன் செயல்களைப் பயன்படுத்தவும்."
@@ -66,7 +65,10 @@
"இது அமைப்பு பயன்பாடு என்பதால் நிறுவல் நீக்கம் செய்ய முடியாது."
"பெயரிடப்படாத கோப்புறை"
"%1$s முடக்கப்பட்டது"
-
+
+ - %1$s ஆப்ஸில் %2$d அறிவிப்புகள் வந்துள்ளன
+ - %1$s ஆப்ஸில் %2$d அறிவிப்பு வந்துள்ளது
+
"பக்கம் %1$d / %2$d"
"முகப்புத் திரை %1$d of %2$d"
"புதிய முகப்புத் திரை பக்கம்"
@@ -82,17 +84,13 @@
"உங்கள் நிர்வாகி முடக்கியுள்ளார்"
"முகப்புத் திரை சுழற்சியை அனுமதி"
"மொபைலைச் சுழற்றும் போது"
-
-
-
-
-
-
+ "அறிவிப்புப் புள்ளிகள்"
+ "ஆன்"
+ "ஆஃப்"
"அறிவிப்பிற்கான அணுகல் தேவை"
"அறிவிப்புப் புள்ளிகளைக் காட்ட, %1$s இன் பயன்பாட்டு அறிவிப்புகளை இயக்கவும்"
"அமைப்புகளை மாற்று"
-
-
+ "அறிவிப்புப் புள்ளிகளைக் காட்டு"
"முகப்புத் திரையில் ஐகானைச் சேர்"
"புதிய பயன்பாடுகளுக்கு"
"ஐகான் வடிவத்தை மாற்று"
diff --git a/res/values-te/strings.xml b/res/values-te/strings.xml
index 4ec35a9e77..04f253936f 100644
--- a/res/values-te/strings.xml
+++ b/res/values-te/strings.xml
@@ -39,8 +39,7 @@
"అప్లికేషన్లను లోడ్ చేస్తోంది…"
"\"%1$s\"కి సరిపోలే అప్లికేషన్లేవీ కనుగొనబడలేదు"
"మరిన్ని యాప్ల కోసం వెతుకు"
-
-
+ "యాప్"
"నోటిఫికేషన్లు"
"షార్ట్కట్ని ఎంచుకోవడం కోసం నొక్కి, పట్టుకోండి."
"రెండుసార్లు నొక్కి, పట్టుకోవడం ద్వారా షార్ట్కట్ని ఎంచుకోండి లేదా అనుకూల చర్యలను ఉపయోగించండి."
@@ -66,7 +65,10 @@
"ఇది సిస్టమ్ యాప్ మరియు దీన్ని అన్ఇన్స్టాల్ చేయడం సాధ్యపడదు."
"పేరు లేని ఫోల్డర్"
"%1$s నిలిపివేయబడింది"
-
+
+ - %1$s, నుంచి %2$d నోటిఫికేషన్లు ఉన్నాయి
+ - %1$s, నుంచి %2$d నోటిఫికేషన్ ఉంది
+
"%2$dలో %1$dవ పేజీ"
"%2$dలో %1$dవ హోమ్ స్క్రీన్"
"కొత్త హోమ్ స్క్రీన్ పేజీ"
@@ -82,17 +84,13 @@
"మీ నిర్వాహకులు నిలిపివేసారు"
"హోమ్ స్క్రీన్ భ్రమణాన్ని అనుమతించండి"
"ఫోన్ను తిప్పినప్పుడు"
-
-
-
-
-
-
+ "నోటిఫికేషన్ డాట్లు"
+ "ఆన్"
+ "ఆఫ్"
"నోటిఫికేషన్ యాక్సెస్ అవసరం"
"నోటిఫికేషన్ డాట్లను చూపించడానికి %1$sకు యాప్ నోటిఫికేషన్లను ఆన్ చేయండి"
"సెట్టింగ్లను మార్చు"
-
-
+ "నోటిఫికేషన్ డాట్లను చూపు"
"హోమ్ స్క్రీన్కి చిహ్నాన్ని జోడించు"
"కొత్త యాప్ల కోసం"
"చిహ్న ఆకారాన్ని మార్చు"
diff --git a/res/values-th/strings.xml b/res/values-th/strings.xml
index 4895c376f9..8473ec0b36 100644
--- a/res/values-th/strings.xml
+++ b/res/values-th/strings.xml
@@ -39,8 +39,7 @@
"กำลังโหลดแอป…"
"ไม่พบแอปที่ตรงกับ \"%1$s\""
"ค้นหาแอปเพิ่มเติม"
-
-
+ "แอป"
"การแจ้งเตือน"
"แตะค้างไว้เพื่อเลือกทางลัด"
"แตะสองครั้งค้างไว้เพื่อเลือกทางลัดหรือใช้การกระทำที่กำหนดเอง"
@@ -66,7 +65,10 @@
"นี่เป็นแอประบบและไม่สามารถถอนการติดตั้งได้"
"โฟลเดอร์ที่ไม่มีชื่อ"
"ปิดใช้ %1$s"
-
+
+ - %1$s มีการแจ้งเตือน %2$d รายการ
+ - %1$s มีการแจ้งเตือน %2$d รายการ
+
"หน้า %1$d จาก %2$d"
"หน้าจอหลัก %1$d จาก %2$d"
"หน้าใหม่ในหน้าจอหลัก"
@@ -82,17 +84,13 @@
"ปิดใช้โดยผู้ดูแลระบบ"
"อนุญาตให้หมุนหน้าจอหลัก"
"เมื่อหมุนโทรศัพท์"
-
-
-
-
-
-
+ "เครื่องหมายจุดแสดงการแจ้งเตือน"
+ "เปิด"
+ "ปิด"
"ต้องได้รับสิทธิ์เข้าถึงการแจ้งเตือน"
"เปิดการแจ้งเตือนแอปของ %1$s เพื่อแสดงจุดแจ้งเตือน"
"เปลี่ยนการตั้งค่า"
-
-
+ "แสดงเครื่องหมายจุดแสดงการแจ้งเตือน"
"เพิ่มไอคอนในหน้าจอหลัก"
"สำหรับแอปใหม่"
"เปลี่ยนรูปร่างไอคอน"
diff --git a/res/values-tl/strings.xml b/res/values-tl/strings.xml
index 90f1bf4999..90b0a182d5 100644
--- a/res/values-tl/strings.xml
+++ b/res/values-tl/strings.xml
@@ -39,8 +39,7 @@
"Naglo-load ng mga app…"
"Walang nahanap na app na tumutugma sa \"%1$s\""
"Maghanap ng higit pang mga app"
-
-
+ "App"
"Mga Notification"
"Pindutin nang matagal para kumuha ng shortcut."
"I-double tap nang matagal para kumuha ng shortcut o gumamit ng mga custom na pagkilos."
@@ -66,7 +65,10 @@
"Isa itong app ng system at hindi maaaring i-uninstall."
"Walang Pangalang Folder"
"Naka-disable ang %1$s"
-
+
+ - May %2$d (na) notification ang %1$s
+ - May %2$d (na) notification ang %1$s
+
"Pahina %1$d ng %2$d"
"Home screen %1$d ng %2$d"
"Bagong page ng home screen"
@@ -82,17 +84,13 @@
"Na-disable ng iyong admin"
"Payagan ang pag-rotate ng Home screen"
"Kailan maro-rotate ang telepono"
-
-
-
-
-
-
+ "Mga notification dot"
+ "Naka-on"
+ "Naka-off"
"Kinakailangan ng access sa notification"
"Upang ipakita ang Mga Notification Dot, i-on ang mga notification ng app para sa %1$s"
"Baguhin ang mga setting"
-
-
+ "Ipakita ang mga notification dot"
"Idagdag ang icon sa Home screen"
"Para sa mga bagong app"
"Baguhin ang hugis ng icon"
diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml
index 34171fc00a..88b85f7fc3 100644
--- a/res/values-tr/strings.xml
+++ b/res/values-tr/strings.xml
@@ -39,8 +39,7 @@
"Uygulamalar yükleniyor…"
"\"%1$s\" ile eşleşen uygulama bulunamadı"
"Başka uygulamalar ara"
-
-
+ "Uygulama"
"Bildirimler"
"Kısayol seçmek için dokunun ve basılı tutun."
"Bir kısayolu seçmek veya özel işlemleri kullanmak için iki kez dokunun ve basılı tutun."
@@ -66,7 +65,10 @@
"Bu bir sistem uygulamasıdır ve yüklemesi kaldırılamaz."
"Adsız Klasör"
"%1$s devre dışı"
-
+
+ - %1$s uygulamasının %2$d bildirimi var
+ - %1$s uygulamasının %2$d bildirimi var
+
"Sayfa %1$d / %2$d"
"Ana ekran %1$d / %2$d"
"Yeni ana ekran sayfası"
@@ -82,17 +84,13 @@
"Yöneticiniz tarafından devre dışı bırakıldı"
"Ana ekranı döndürmeye izin ver"
"Telefon döndürüldüğünde"
-
-
-
-
-
-
+ "Bildirim noktaları"
+ "Açık"
+ "Kapalı"
"Bildirim erişimi gerekli"
"Bildirim Noktaları\'nı göstermek için %1$s uygulamasının bildirimlerini açın"
"Ayarları değiştir"
-
-
+ "Bildirim noktalarını göster"
"Ana ekrana simge ekle"
"Yeni uygulamalar için"
"Simge şeklini değiştir"
diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml
index 17dac15971..e62cb52c23 100644
--- a/res/values-uk/strings.xml
+++ b/res/values-uk/strings.xml
@@ -39,8 +39,7 @@
"Завантаження додатків…"
"Немає додатків для запиту \"%1$s\""
"Шукати ще додатки"
-
-
+ "Додаток"
"Сповіщення"
"Натисніть і втримуйте, щоб вибрати ярлик."
"Двічі натисніть і втримуйте, щоб вибрати ярлик, або виконайте іншу дію."
@@ -66,7 +65,12 @@
"Це системна програма, її неможливо видалити."
"Папка без назви"
"%1$s вимкнено"
-
+
+ - Додаток %1$s має %2$d сповіщення
+ - Додаток %1$s має %2$d сповіщення
+ - Додаток %1$s має %2$d сповіщень
+ - Додаток %1$s має %2$d сповіщення
+
"Сторінка %1$d з %2$d"
"Головний екран %1$d з %2$d"
"Нова сторінка головного екрана"
@@ -82,17 +86,13 @@
"Вимкнув адміністратор"
"Дозволити обертання головного екрана"
"Коли телефон обертається"
-
-
-
-
-
-
+ "Значки сповіщень"
+ "Увімкнено"
+ "Вимкнено"
"Потрібен доступ до сповіщень"
"Щоб показувати значки сповіщень, увімкніть сповіщення в додатку %1$s"
"Змінити налаштування"
-
-
+ "Показувати значки сповіщень"
"Додати значок на головний екран"
"Для нових додатків"
"Змінити форму значка"
@@ -104,7 +104,7 @@
"Сльоза"
"Змінюється форма значка"
"Невідомо"
- "Вилучити значок"
+ "Прибрати"
"Шукати"
"Цей додаток не встановлено"
"Додаток для цього значка не встановлено. Можна видалити значок або знайти додаток і встановити його вручну."
diff --git a/res/values-ur/strings.xml b/res/values-ur/strings.xml
index e8b6b6b7ff..fde98c90f5 100644
--- a/res/values-ur/strings.xml
+++ b/res/values-ur/strings.xml
@@ -39,8 +39,7 @@
"ایپس لوڈ کی جا رہی ہیں…"
"\"%1$s\" سے مماثل کوئی ایپس نہیں ملیں"
"مزید ایپس تلاش کریں"
-
-
+ "ایپ"
"اطلاعات"
"ایک شارٹ کٹ منتخب کرنے کیلئے ٹچ کر کے دبائے رکھیں۔"
"ایک شارٹ کٹ منتخب کرنے یا حسب ضرورت کارروائیاں استعمال کرنے کیلئے دو بار تھپتھپائیں اور دبائے رکھیں۔"
@@ -66,7 +65,10 @@
"یہ ایک سسٹم ایپ ہے اور اسے اَن انسٹال نہیں کیا جا سکتا ہے۔"
"بلا نام فولڈر"
"%1$s غیر فعال ہے"
-
+
+ - %1$s میں%2$d اطلاعات ہیں
+ - %1$s میں%2$d اطلاع ہے
+
"صفحہ %1$d از %2$d"
"ہوم اسکرین %1$d از %2$d"
"نیا ہوم اسکرین صفحہ"
@@ -82,17 +84,13 @@
"آپ کے منتظم کی طرف سے غیر فعال کر دیا گیا"
"ہوم اسکرین گھمانے کی اجازت دیں"
"جب فون گھمایا جاتا ہے"
-
-
-
-
-
-
+ "اطلاعاتی ڈاٹس"
+ "آن ہے"
+ "آف ہے"
"اطلاعاتی رسائی درکار ہے"
"اطلاعاتی ڈاٹس دکھانے کی خاطر %1$s کیلئے ایپ کی اطلاعات آن کریں"
"ترتیبات تبدیل کریں"
-
-
+ "اطلاعاتی ڈاٹس دکھائیں"
"آئیکن کو ہوم اسکرین میں شامل کریں"
"نئی ایپس کیلئے"
"آئیکن کی شکل تبدیل کریں"
diff --git a/res/values-uz/strings.xml b/res/values-uz/strings.xml
index 3165726977..015dcda745 100644
--- a/res/values-uz/strings.xml
+++ b/res/values-uz/strings.xml
@@ -39,8 +39,7 @@
"Ilovalar yuklanmoqda…"
"“%1$s” bilan mos hech qanday ilova topilmadi"
"Boshqa ilovalarni qidirish"
-
-
+ "Ilova"
"Bildirishnomalar"
"Yorliqni tanlab olish uchun bosib turing."
"Ikki marta bosib va bosib turgan holatda yorliqni tanlang yoki maxsus amaldan foydalaning."
@@ -66,7 +65,10 @@
"Bu tizim ilovasi, shuning uchun o‘chirib bo‘lmaydi."
"Nomsiz jild"
"%1$s ilovasi o‘chirib qo‘yildi"
-
+
+ - %1$s ilovasida %2$d ta bildirishnoma bor
+ - %1$s ilovasida %2$d ta bildirishnoma bor
+
"%2$ddan %1$d ta sahifa"
"Uy ekrani %2$ddan %1$d"
"Yangi bosh ekran sahifasi"
@@ -82,17 +84,13 @@
"Administrator tomonidan o‘chirilgan"
"Asosiy ekranni aylantirishga ruxsat berish"
"Telefon burilganda"
-
-
-
-
-
-
+ "Bildirishnoma belgilari"
+ "Yoniq"
+ "Yoqilmagan"
"Bildirishnomalarga ruxsat berilmagan"
"Bildirishnoma belgilarini ko‘rsatish uchun %1$s ilovasida bildirishnomalarni yoqing"
"Sozlamalarni o‘zgartirish"
-
-
+ "Bildirishnoma belgilarini chiqarish"
"Bosh ekranga ikonka chiqarish"
"Yangi o‘rnatilgan ilovalar ikonkasini bosh ekranga chiqarish"
"Ikonka shaklini o‘zgartirish"
diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml
index 254420d13d..69b17c6836 100644
--- a/res/values-vi/strings.xml
+++ b/res/values-vi/strings.xml
@@ -39,8 +39,7 @@
"Đang tải ứng dụng…"
"Không tìm thấy ứng dụng nào phù hợp với \"%1$s\""
"Tìm kiếm thêm ứng dụng"
-
-
+ "Ứng dụng"
"Thông báo"
"Chạm và giữ để chọn lối tắt."
"Nhấn đúp và giữ để chọn lối tắt hoặc sử dụng hành động tùy chỉnh."
@@ -66,7 +65,10 @@
"Đây là ứng dụng hệ thống và không thể gỡ cài đặt."
"Thư mục chưa đặt tên"
"Đã vô hiệu hóa %1$s"
-
+
+ - %1$s, có %2$d thông báo
+ - %1$s, có %2$d thông báo
+
"Trang %1$d / %2$d"
"Màn hình chính %1$d / %2$d"
"Trang màn hình chính mới"
@@ -82,17 +84,13 @@
"Bị tắt bởi quản trị viên của bạn"
"Cho phép xoay Màn hình chính"
"Khi xoay điện thoại"
-
-
-
-
-
-
+ "Dấu chấm thông báo"
+ "Bật"
+ "Tắt"
"Cần quyền truy cập thông báo"
"Để hiển thị Dấu chấm thông báo, hãy bật thông báo ứng dụng cho %1$s"
"Thay đổi cài đặt"
-
-
+ "Hiển thị dấu chấm thông báo"
"Thêm biểu tượng vào màn hình chính"
"Cho ứng dụng mới"
"Thay đổi hình dạng biểu tượng"
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index f1f3b9759c..cbec49ec9a 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -39,8 +39,7 @@
"正在加载应用…"
"未找到与“%1$s”相符的应用"
"搜索更多应用"
-
-
+ "应用"
"通知"
"触摸并按住快捷方式即可选择快捷方式。"
"点按两次并按住快捷方式即可选择快捷方式,您也可以使用自定义操作。"
@@ -66,7 +65,10 @@
"这是系统应用,无法卸载。"
"未命名文件夹"
"已停用%1$s"
-
+
+ - %1$s,有 %2$d 个通知
+ - %1$s,有 %2$d 个通知
+
"第%1$d页,共%2$d页"
"主屏幕:第%1$d屏,共%2$d屏"
"主屏幕新页面"
@@ -82,17 +84,13 @@
"已被您的管理员停用"
"允许旋转主屏幕"
"手机旋转时"
-
-
-
-
-
-
+ "通知圆点"
+ "开启"
+ "关闭"
"需要获取通知使用权"
"要显示通知圆点,请开启%1$s的应用通知功能"
"更改设置"
-
-
+ "显示通知圆点"
"将图标添加到主屏幕"
"适用于新应用"
"更改图标形状"
diff --git a/res/values-zh-rHK/strings.xml b/res/values-zh-rHK/strings.xml
index 0f70e9ea9d..648b1cc279 100644
--- a/res/values-zh-rHK/strings.xml
+++ b/res/values-zh-rHK/strings.xml
@@ -39,8 +39,7 @@
"正在載入應用程式…"
"找不到與「%1$s」相符的應用程式"
"搜尋更多應用程式"
-
-
+ "應用程式"
"通知"
"按住捷徑即可選取。"
"連㩒兩下之後繼續㩒住,就可以揀選捷徑或者用自訂嘅操作。"
@@ -66,7 +65,10 @@
"這是系統應用程式,無法將其解除安裝。"
"未命名的資料夾"
"「%1$s」已停用"
-
+
+ - %1$s,有 %2$d 項通知
+ - %1$s,有 %2$d 項通知
+
"第 %1$d 頁,共 %2$d 頁"
"主畫面 %1$d,共 %2$d 個"
"新主畫面頁面"
@@ -82,17 +84,13 @@
"已由您的管理員停用"
"允許主畫面旋轉"
"當手機旋轉時"
-
-
-
-
-
-
+ "通知圓點"
+ "開啟"
+ "關閉"
"需要獲取通知存取權"
"如要顯示「通知圓點」,請開啟「%1$s」的應用程式通知功能"
"變更設定"
-
-
+ "顯示通知圓點"
"將圖示加到主畫面"
"適用於新安裝的應用程式"
"變更圖示形狀"
diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml
index 652679a017..74f2949b39 100644
--- a/res/values-zh-rTW/strings.xml
+++ b/res/values-zh-rTW/strings.xml
@@ -39,8 +39,7 @@
"正在載入應用程式…"
"找不到與「%1$s」相符的應用程式"
"搜尋更多應用程式"
-
-
+ "應用程式"
"通知"
"按住捷徑即可選取。"
"輕觸兩下並按住捷徑即可選取,你也可以使用自訂動作。"
@@ -66,7 +65,10 @@
"這是系統應用程式,不可解除安裝。"
"未命名的資料夾"
"已停用 %1$s"
-
+
+ - %1$s,有 %2$d 則通知
+ - %1$s,有 %2$d 則通知
+
"第 %1$d 頁,共 %2$d 頁"
"主螢幕:第 %1$d 頁,共 %2$d 頁"
"新的主畫面頁面"
@@ -82,17 +84,13 @@
"已由你的管理員停用"
"允許旋轉主螢幕"
"當手機旋轉時"
-
-
-
-
-
-
+ "通知圓點"
+ "開啟"
+ "關閉"
"需要取得通知存取權"
"如要顯示通知圓點,請開啟「%1$s」的應用程式通知功能"
"變更設定"
-
-
+ "顯示通知圓點"
"將圖示加到主螢幕"
"適用於新安裝的應用程式"
"變更圖示形狀"
diff --git a/res/values-zu/strings.xml b/res/values-zu/strings.xml
index 22fba2bc06..89893fc6ff 100644
--- a/res/values-zu/strings.xml
+++ b/res/values-zu/strings.xml
@@ -39,8 +39,7 @@
"Ilayisha izinhlelo zokusebenza..."
"Azikho izinhlelo zokusebenza ezitholiwe ezifana ne-\"%1$s\""
"Sesha izinhlelo zokusebenza eziningi"
-
-
+ "Uhlelo lokusebenza"
"Izaziso"
"Thinta futhi ubambe ukuze ukhethe isinqamuleli."
"Thepha kabili uphinde ubambe ukuze uphakamise isinqamuleli noma usebenzise izenzo zangokwezifiso."
@@ -66,7 +65,10 @@
"Lolu uhlelo lokusebenza lwesistimu futhi alikwazi ukukhishwa."
"Ifolda engenagama"
"Kukhutshaziwe %1$s"
-
+
+ - %1$s, unezaziso ezingu-%2$d
+ - %1$s, unezaziso ezingu-%2$d
+
"Ikhasi elingu-%1$d kwangu-%2$d"
"Isikrini sasekhaya esingu-%1$d se-%2$d"
"Ikhasi elisha lesikrini sasekhaya"
@@ -82,17 +84,13 @@
"Kukhutshazwe umlawuli wakho"
"Vumela ukuphendukiswa kwesikrini sasekhaya"
"Uma ifoni iphendukiswa"
-
-
-
-
-
-
+ "Amacashazi esaziso"
+ "Vuliwe"
+ "Valiwe"
"Ukufinyelela izaziso kuyadingeka"
"Ukuze ubonisa amcashazi esaziso, vula izaziso zohlelo lokusebenza ze-%1$s"
"Shintsha izilungiselelo"
-
-
+ "Bonisa amacashazi esaziso"
"Engeza isithonjana eskrinini sasekhaya"
"Kwezinhlelo zokusebenza ezintsha"
"Shintsha isimo sesithonjana"
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index 29bd3c8879..8c4dd1efdc 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -93,10 +93,8 @@
-
+
-
-
@@ -106,13 +104,21 @@
+
+
+
+
+
+
+
+
+
-
-
-
+
+
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 8adae36187..078ce60a62 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -36,7 +36,7 @@
2dp
0dp
- 80dp
+ 34dp
0dp
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 3f01278760..b1eff24578 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -205,23 +205,23 @@
For new apps
-
- Change icon shape
-
- on Home screen
-
- Use system default
-
- Square
-
- Squircle
-
- Circle
-
- Teardrop
+
+ Change icon shape
+
+ on Home screen
+
+ Use system default
+
+ Square
+
+ Squircle
+
+ Circle
+
+ Teardrop
-
- Applying icon shape changes
+
+ Applying icon shape changes
Unknown
diff --git a/res/xml/default_workspace_3x3.xml b/res/xml/default_workspace_3x3.xml
index 8d99404504..31376e1d5e 100644
--- a/res/xml/default_workspace_3x3.xml
+++ b/res/xml/default_workspace_3x3.xml
@@ -68,21 +68,4 @@
-
-
-
-
-
-
-
-
-
-
-
diff --git a/res/xml/default_workspace_4x4.xml b/res/xml/default_workspace_4x4.xml
index 979a1b4c84..bf3c62c77d 100644
--- a/res/xml/default_workspace_4x4.xml
+++ b/res/xml/default_workspace_4x4.xml
@@ -16,8 +16,48 @@
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/res/xml/device_profiles.xml b/res/xml/device_profiles.xml
index ef6e14506b..88b1bc95ae 100644
--- a/res/xml/device_profiles.xml
+++ b/res/xml/device_profiles.xml
@@ -17,158 +17,109 @@
-
+ launcher:defaultLayoutId="@xml/default_workspace_3x3" >
-
+
-
+
+
+
+
+ launcher:numHotseatIcons="4"
+ launcher:defaultLayoutId="@xml/default_workspace_4x4" >
-
+
-
+
-
+
-
+
-
+
+
+
+
+ launcher:defaultLayoutId="@xml/default_workspace_5x5" >
-
+
-
+
-
+
\ No newline at end of file
diff --git a/res/xml/dw_phone_hotseat.xml b/res/xml/dw_phone_hotseat.xml
deleted file mode 100644
index c691ebc3da..0000000000
--- a/res/xml/dw_phone_hotseat.xml
+++ /dev/null
@@ -1,70 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/res/xml/dw_tablet_hotseat.xml b/res/xml/dw_tablet_hotseat.xml
deleted file mode 100644
index 6fe7f93d82..0000000000
--- a/res/xml/dw_tablet_hotseat.xml
+++ /dev/null
@@ -1,84 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/res/xml/launcher_preferences.xml b/res/xml/launcher_preferences.xml
index be3cb0e28f..7e7220813a 100644
--- a/res/xml/launcher_preferences.xml
+++ b/res/xml/launcher_preferences.xml
@@ -44,15 +44,6 @@
android:defaultValue="@bool/allow_rotation"
android:persistent="true" />
-
-
notAnimated = ArgumentCaptor.forClass(ArrayList.class);
@@ -141,7 +138,7 @@ public class AddWorkspaceItemsTaskTest extends BaseModelUpdateTaskTestCase {
assertTrue(animated.getValue().contains(info2));
}
- private int setupWorkspaceWithHoles(int startId, int screenId, Rect... holes) {
+ private int setupWorkspaceWithHoles(int startId, int screenId, Rect... holes) throws Exception {
GridOccupancy occupancy = new GridOccupancy(idp.numColumns, idp.numRows);
occupancy.markCells(0, 0, idp.numColumns, idp.numRows, true);
for (Rect r : holes) {
@@ -151,6 +148,7 @@ public class AddWorkspaceItemsTaskTest extends BaseModelUpdateTaskTestCase {
existingScreens.add(screenId);
screenOccupancy.append(screenId, occupancy);
+ ExecutorService executor = Executors.newSingleThreadExecutor();
for (int x = 0; x < idp.numColumns; x++) {
for (int y = 0; y < idp.numRows; y++) {
if (!occupancy.cells[x][y]) {
@@ -165,27 +163,19 @@ public class AddWorkspaceItemsTaskTest extends BaseModelUpdateTaskTestCase {
info.cellY = y;
info.container = LauncherSettings.Favorites.CONTAINER_DESKTOP;
bgDataModel.addItem(targetContext, info, false);
+
+ executor.execute(() -> {
+ ContentWriter writer = new ContentWriter(targetContext);
+ info.writeToValues(writer);
+ writer.put(Favorites._ID, info.id);
+ targetContext.getContentResolver().insert(Favorites.CONTENT_URI,
+ writer.getValues(targetContext));
+ });
}
}
+
+ executor.submit(() -> null).get();
+ executor.shutdown();
return startId;
}
-
- private void commitScreensToDb() throws Exception {
- LauncherSettings.Settings.call(targetContext.getContentResolver(),
- LauncherSettings.Settings.METHOD_CREATE_EMPTY_DB);
-
- Uri uri = LauncherSettings.WorkspaceScreens.CONTENT_URI;
- ArrayList ops = new ArrayList<>();
- // Clear the table
- ops.add(ContentProviderOperation.newDelete(uri).build());
- int count = existingScreens.size();
- for (int i = 0; i < count; i++) {
- ContentValues v = new ContentValues();
- int screenId = existingScreens.get(i);
- v.put(LauncherSettings.WorkspaceScreens._ID, screenId);
- v.put(LauncherSettings.WorkspaceScreens.SCREEN_RANK, i);
- ops.add(ContentProviderOperation.newInsert(uri).withValues(v).build());
- }
- targetContext.getContentResolver().applyBatch(LauncherProvider.AUTHORITY, ops);
- }
}
diff --git a/tests/src/com/android/launcher3/model/DbDowngradeHelperTest.java b/robolectric_tests/src/com/android/launcher3/model/DbDowngradeHelperTest.java
similarity index 81%
rename from tests/src/com/android/launcher3/model/DbDowngradeHelperTest.java
rename to robolectric_tests/src/com/android/launcher3/model/DbDowngradeHelperTest.java
index 0903ddc16d..a46617ec28 100644
--- a/tests/src/com/android/launcher3/model/DbDowngradeHelperTest.java
+++ b/robolectric_tests/src/com/android/launcher3/model/DbDowngradeHelperTest.java
@@ -20,14 +20,17 @@ import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertNotSame;
import static junit.framework.Assert.assertTrue;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
import android.content.ContentValues;
import android.content.Context;
+import android.content.res.Resources;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
import com.android.launcher3.LauncherProvider;
import com.android.launcher3.LauncherProvider.DatabaseHelper;
@@ -37,14 +40,15 @@ import com.android.launcher3.R;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
import java.io.File;
/**
* Tests for {@link DbDowngradeHelper}
*/
-@SmallTest
-@RunWith(AndroidJUnit4.class)
+@RunWith(RobolectricTestRunner.class)
public class DbDowngradeHelperTest {
private static final String SCHEMA_FILE = "test_schema.json";
@@ -56,35 +60,47 @@ public class DbDowngradeHelperTest {
@Before
public void setup() {
- mContext = InstrumentationRegistry.getTargetContext();
+ mContext = RuntimeEnvironment.application;
mSchemaFile = mContext.getFileStreamPath(SCHEMA_FILE);
mDbFile = mContext.getDatabasePath(DB_FILE);
}
+ @Test
+ public void testDowngradeSchemaMatchesVersion() throws Exception {
+ mSchemaFile.delete();
+ assertFalse(mSchemaFile.exists());
+ DbDowngradeHelper.updateSchemaFile(mSchemaFile, 0, mContext);
+ assertEquals(LauncherProvider.SCHEMA_VERSION, DbDowngradeHelper.parse(mSchemaFile).version);
+ }
+
@Test
public void testUpdateSchemaFile() throws Exception {
- Context myContext = InstrumentationRegistry.getContext();
- int testResId = myContext.getResources().getIdentifier(
- "db_schema_v10", "raw", myContext.getPackageName());
+ // Setup mock resources
+ Resources res = spy(mContext.getResources());
+ doAnswer(i ->this.getClass().getResourceAsStream("/db_schema_v10.json"))
+ .when(res).openRawResource(eq(R.raw.downgrade_schema));
+ Context context = spy(mContext);
+ when(context.getResources()).thenReturn(res);
+
mSchemaFile.delete();
assertFalse(mSchemaFile.exists());
- DbDowngradeHelper.updateSchemaFile(mSchemaFile, 10, myContext, testResId);
+ DbDowngradeHelper.updateSchemaFile(mSchemaFile, 10, context);
assertTrue(mSchemaFile.exists());
assertEquals(10, DbDowngradeHelper.parse(mSchemaFile).version);
// Schema is updated on version upgrade
assertTrue(mSchemaFile.setLastModified(0));
- DbDowngradeHelper.updateSchemaFile(mSchemaFile, 11, myContext, testResId);
+ DbDowngradeHelper.updateSchemaFile(mSchemaFile, 11, context);
assertNotSame(0, mSchemaFile.lastModified());
// Schema is not updated when version is same
assertTrue(mSchemaFile.setLastModified(0));
- DbDowngradeHelper.updateSchemaFile(mSchemaFile, 10, myContext, testResId);
+ DbDowngradeHelper.updateSchemaFile(mSchemaFile, 10, context);
assertEquals(0, mSchemaFile.lastModified());
// Schema is not updated on version downgrade
- DbDowngradeHelper.updateSchemaFile(mSchemaFile, 3, myContext, testResId);
+ DbDowngradeHelper.updateSchemaFile(mSchemaFile, 3, context);
assertEquals(0, mSchemaFile.lastModified());
}
@@ -143,8 +159,7 @@ public class DbDowngradeHelperTest {
mSchemaFile.delete();
mDbFile.delete();
- DbDowngradeHelper.updateSchemaFile(mSchemaFile, LauncherProvider.SCHEMA_VERSION, mContext,
- R.raw.downgrade_schema);
+ DbDowngradeHelper.updateSchemaFile(mSchemaFile, LauncherProvider.SCHEMA_VERSION, mContext);
DatabaseHelper dbHelper = new DatabaseHelper(mContext, null, DB_FILE) {
@Override
diff --git a/robolectric_tests/src/com/android/launcher3/model/GridSizeMigrationTaskTest.java b/robolectric_tests/src/com/android/launcher3/model/GridSizeMigrationTaskTest.java
index 67580ddd8d..d4188aa8e8 100644
--- a/robolectric_tests/src/com/android/launcher3/model/GridSizeMigrationTaskTest.java
+++ b/robolectric_tests/src/com/android/launcher3/model/GridSizeMigrationTaskTest.java
@@ -1,5 +1,7 @@
package com.android.launcher3.model;
+import static com.android.launcher3.model.GridSizeMigrationTask.getWorkspaceScreenIds;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
@@ -10,7 +12,6 @@ import android.database.Cursor;
import android.graphics.Point;
import com.android.launcher3.InvariantDeviceProfile;
-import com.android.launcher3.LauncherModel;
import com.android.launcher3.LauncherProvider;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.config.FlagOverrideRule;
@@ -55,7 +56,6 @@ public class GridSizeMigrationTaskTest {
@Before
public void setUp() {
-
mValidPackages = new HashSet<>();
mValidPackages.add(TEST_PACKAGE);
mIdp = new InvariantDeviceProfile();
@@ -307,11 +307,6 @@ public class GridSizeMigrationTaskTest {
LauncherSettings.Settings.call(mContext.getContentResolver(),
LauncherSettings.Settings.METHOD_NEW_SCREEN_ID);
- ContentValues v = new ContentValues();
- v.put(LauncherSettings.WorkspaceScreens._ID, screenId);
- v.put(LauncherSettings.WorkspaceScreens.SCREEN_RANK, i);
- mContext.getContentResolver().insert(LauncherSettings.WorkspaceScreens.CONTENT_URI, v);
-
ids[i] = new int[typeArray[i].length][];
for (int y = 0; y < typeArray[i].length; y++) {
ids[i][y] = new int[typeArray[i][y].length];
@@ -326,7 +321,6 @@ public class GridSizeMigrationTaskTest {
}
}
- IntArray allScreens = LauncherModel.loadWorkspaceScreensDb(mContext);
return ids;
}
@@ -336,7 +330,7 @@ public class GridSizeMigrationTaskTest {
* represent the workspace grid.
*/
private void verifyWorkspace(int[][][] ids) {
- IntArray allScreens = LauncherModel.loadWorkspaceScreensDb(mContext);
+ IntArray allScreens = getWorkspaceScreenIds(mContext);
assertEquals(ids.length, allScreens.size());
int total = 0;
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index c1c12046e8..812cf9f8e4 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -207,11 +207,10 @@ public class DeviceProfile {
// Add a bit of space between nav bar and hotseat in multi-window vertical bar layout.
hotseatBarSidePaddingStartPx = isMultiWindowMode && isVerticalBarLayout()
? edgeMarginPx : 0;
- hotseatBarSizePx = isVerticalBarLayout()
- ? Utilities.pxFromDp(inv.iconSize, dm) + hotseatBarSidePaddingStartPx
- + hotseatBarSidePaddingEndPx
- : res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_size)
- + hotseatBarTopPaddingPx + hotseatBarBottomPaddingPx;
+ hotseatBarSizePx = Utilities.pxFromDp(inv.iconSize, dm) + (isVerticalBarLayout()
+ ? (hotseatBarSidePaddingStartPx + hotseatBarSidePaddingEndPx)
+ : (res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_extra_vertical_size)
+ + hotseatBarTopPaddingPx + hotseatBarBottomPaddingPx));
// Calculate all of the remaining variables.
updateAvailableDimensions(dm, res);
diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java
index 0b2f4d921e..257e46c2f4 100644
--- a/src/com/android/launcher3/InvariantDeviceProfile.java
+++ b/src/com/android/launcher3/InvariantDeviceProfile.java
@@ -24,6 +24,8 @@ import android.content.res.Configuration;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.graphics.Point;
+import android.text.TextUtils;
+import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.Xml;
@@ -32,15 +34,12 @@ import android.view.WindowManager;
import com.android.launcher3.util.ConfigMonitor;
import com.android.launcher3.util.MainThreadInitializedObject;
-import com.android.launcher3.util.Thunk;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
import androidx.annotation.VisibleForTesting;
@@ -50,6 +49,8 @@ public class InvariantDeviceProfile {
public static final MainThreadInitializedObject INSTANCE =
new MainThreadInitializedObject<>(InvariantDeviceProfile::new);
+ private static final String KEY_IDP_GRIP_NAME = "idp_grid_name";
+
private static final float ICON_SIZE_DEFINED_IN_APP_DP = 48;
public static final int CHANGE_FLAG_GRID = 1 << 0;
@@ -63,11 +64,6 @@ public class InvariantDeviceProfile {
// used to offset float not being able to express extremely small weights in extreme cases.
private static float WEIGHT_EFFICIENT = 100000f;
- // Profile-defining invariant properties
- private String name;
- private float minWidthDps;
- private float minHeightDps;
-
/**
* Number of icons per row and column in the workspace.
*/
@@ -90,7 +86,7 @@ public class InvariantDeviceProfile {
*/
public int numHotseatIcons;
- int defaultLayoutId;
+ public int defaultLayoutId;
int demoModeLayoutId;
public DeviceProfile landscapeProfile;
@@ -105,37 +101,26 @@ public class InvariantDeviceProfile {
public InvariantDeviceProfile() {}
private InvariantDeviceProfile(InvariantDeviceProfile p) {
- this(p.name, p.minWidthDps, p.minHeightDps, p.numRows, p.numColumns,
- p.numFolderRows, p.numFolderColumns,
- p.iconSize, p.landscapeIconSize, p.iconTextSize, p.numHotseatIcons,
- p.defaultLayoutId, p.demoModeLayoutId);
- }
-
- private InvariantDeviceProfile(String n, float w, float h, int r, int c, int fr, int fc,
- float is, float lis, float its, int hs, int dlId, int dmlId) {
- name = n;
- minWidthDps = w;
- minHeightDps = h;
- numRows = r;
- numColumns = c;
- numFolderRows = fr;
- numFolderColumns = fc;
- iconSize = is;
- landscapeIconSize = lis;
- iconTextSize = its;
- numHotseatIcons = hs;
- defaultLayoutId = dlId;
- demoModeLayoutId = dmlId;
+ numRows = p.numRows;
+ numColumns = p.numColumns;
+ numFolderRows = p.numFolderRows;
+ numFolderColumns = p.numFolderColumns;
+ iconSize = p.iconSize;
+ landscapeIconSize = p.landscapeIconSize;
+ iconTextSize = p.iconTextSize;
+ numHotseatIcons = p.numHotseatIcons;
+ defaultLayoutId = p.defaultLayoutId;
+ demoModeLayoutId = p.demoModeLayoutId;
}
@TargetApi(23)
private InvariantDeviceProfile(Context context) {
- initGrid(context);
+ initGrid(context, Utilities.getPrefs(context).getString(KEY_IDP_GRIP_NAME, null));
mConfigMonitor = new ConfigMonitor(context,
APPLY_CONFIG_AT_RUNTIME.get() ? this::onConfigChanged : this::killProcess);
}
- private void initGrid(Context context) {
+ private void initGrid(Context context, String gridName) {
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
DisplayMetrics dm = new DisplayMetrics();
@@ -145,16 +130,18 @@ public class InvariantDeviceProfile {
Point largestSize = new Point();
display.getCurrentSizeRange(smallestSize, largestSize);
+ ArrayList allOptions = getPredefinedDeviceProfiles(context, gridName);
// This guarantees that width < height
- minWidthDps = Utilities.dpiFromPx(Math.min(smallestSize.x, smallestSize.y), dm);
- minHeightDps = Utilities.dpiFromPx(Math.min(largestSize.x, largestSize.y), dm);
+ float minWidthDps = Utilities.dpiFromPx(Math.min(smallestSize.x, smallestSize.y), dm);
+ float minHeightDps = Utilities.dpiFromPx(Math.min(largestSize.x, largestSize.y), dm);
+ // Sort the profiles based on the closeness to the device size
+ allOptions.sort((a, b) ->
+ Float.compare(dist(minWidthDps, minHeightDps, a.minWidthDps, a.minHeightDps),
+ dist(minWidthDps, minHeightDps, b.minWidthDps, b.minHeightDps)));
+ DisplayOption interpolatedDisplayOption =
+ invDistWeightedInterpolate(minWidthDps, minHeightDps, allOptions);
- ArrayList closestProfiles = findClosestDeviceProfiles(
- minWidthDps, minHeightDps, getPredefinedDeviceProfiles(context));
- InvariantDeviceProfile interpolatedDeviceProfileOut =
- invDistWeightedInterpolate(minWidthDps, minHeightDps, closestProfiles);
-
- InvariantDeviceProfile closestProfile = closestProfiles.get(0);
+ GridOption closestProfile = allOptions.get(0).grid;
numRows = closestProfile.numRows;
numColumns = closestProfile.numColumns;
numHotseatIcons = closestProfile.numHotseatIcons;
@@ -162,11 +149,15 @@ public class InvariantDeviceProfile {
demoModeLayoutId = closestProfile.demoModeLayoutId;
numFolderRows = closestProfile.numFolderRows;
numFolderColumns = closestProfile.numFolderColumns;
+ if (!closestProfile.name.equals(gridName)) {
+ Utilities.getPrefs(context).edit()
+ .putString(KEY_IDP_GRIP_NAME, closestProfile.name).apply();
+ }
- iconSize = interpolatedDeviceProfileOut.iconSize;
- landscapeIconSize = interpolatedDeviceProfileOut.landscapeIconSize;
+ iconSize = interpolatedDisplayOption.iconSize;
+ landscapeIconSize = interpolatedDisplayOption.landscapeIconSize;
iconBitmapSize = Utilities.pxFromDp(iconSize, dm);
- iconTextSize = interpolatedDeviceProfileOut.iconTextSize;
+ iconTextSize = interpolatedDisplayOption.iconTextSize;
fillResIconDpi = getLauncherIconDensity(iconBitmapSize);
// If the partner customization apk contains any grid overrides, apply them
@@ -210,7 +201,7 @@ public class InvariantDeviceProfile {
InvariantDeviceProfile oldProfile = new InvariantDeviceProfile(this);
// Re-init grid
- initGrid(context);
+ initGrid(context, Utilities.getPrefs(context).getString(KEY_IDP_GRIP_NAME, null));
int changeFlags = 0;
if (numRows != oldProfile.numRows ||
@@ -234,41 +225,53 @@ public class InvariantDeviceProfile {
}
}
- ArrayList getPredefinedDeviceProfiles(Context context) {
- ArrayList profiles = new ArrayList<>();
+ static ArrayList getPredefinedDeviceProfiles(Context context, String gridName) {
+ ArrayList profiles = new ArrayList<>();
try (XmlResourceParser parser = context.getResources().getXml(R.xml.device_profiles)) {
final int depth = parser.getDepth();
int type;
while (((type = parser.next()) != XmlPullParser.END_TAG ||
parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) {
- if ((type == XmlPullParser.START_TAG) && "profile".equals(parser.getName())) {
- TypedArray a = context.obtainStyledAttributes(
- Xml.asAttributeSet(parser), R.styleable.InvariantDeviceProfile);
- int numRows = a.getInt(R.styleable.InvariantDeviceProfile_numRows, 0);
- int numColumns = a.getInt(R.styleable.InvariantDeviceProfile_numColumns, 0);
- float iconSize = a.getFloat(R.styleable.InvariantDeviceProfile_iconSize, 0);
- profiles.add(new InvariantDeviceProfile(
- a.getString(R.styleable.InvariantDeviceProfile_name),
- a.getFloat(R.styleable.InvariantDeviceProfile_minWidthDps, 0),
- a.getFloat(R.styleable.InvariantDeviceProfile_minHeightDps, 0),
- numRows,
- numColumns,
- a.getInt(R.styleable.InvariantDeviceProfile_numFolderRows, numRows),
- a.getInt(R.styleable.InvariantDeviceProfile_numFolderColumns, numColumns),
- iconSize,
- a.getFloat(R.styleable.InvariantDeviceProfile_landscapeIconSize, iconSize),
- a.getFloat(R.styleable.InvariantDeviceProfile_iconTextSize, 0),
- a.getInt(R.styleable.InvariantDeviceProfile_numHotseatIcons, numColumns),
- a.getResourceId(R.styleable.InvariantDeviceProfile_defaultLayoutId, 0),
- a.getResourceId(R.styleable.InvariantDeviceProfile_demoModeLayoutId, 0)));
- a.recycle();
+ if ((type == XmlPullParser.START_TAG) && "grid-option".equals(parser.getName())) {
+
+ GridOption gridOption = new GridOption(context, Xml.asAttributeSet(parser));
+ final int displayDepth = parser.getDepth();
+ while (((type = parser.next()) != XmlPullParser.END_TAG ||
+ parser.getDepth() > displayDepth)
+ && type != XmlPullParser.END_DOCUMENT) {
+ if ((type == XmlPullParser.START_TAG) && "display-option".equals(
+ parser.getName())) {
+ profiles.add(new DisplayOption(
+ gridOption, context, Xml.asAttributeSet(parser)));
+ }
+ }
}
}
} catch (IOException|XmlPullParserException e) {
throw new RuntimeException(e);
}
- return profiles;
+
+ ArrayList filteredProfiles = new ArrayList<>();
+ if (!TextUtils.isEmpty(gridName)) {
+ for (DisplayOption option : profiles) {
+ if (gridName.equals(option.grid.name)) {
+ filteredProfiles.add(option);
+ }
+ }
+ }
+ if (filteredProfiles.isEmpty()) {
+ // No grid found, use the default options
+ for (DisplayOption option : profiles) {
+ if (option.canBeDefault) {
+ filteredProfiles.add(option);
+ }
+ }
+ }
+ if (filteredProfiles.isEmpty()) {
+ throw new RuntimeException("No display option with canBeDefault=true");
+ }
+ return filteredProfiles;
}
private int getLauncherIconDensity(int requiredSize) {
@@ -307,60 +310,40 @@ public class InvariantDeviceProfile {
}
}
- @Thunk float dist(float x0, float y0, float x1, float y1) {
+ private static float dist(float x0, float y0, float x1, float y1) {
return (float) Math.hypot(x1 - x0, y1 - y0);
}
/**
* Returns the closest device profiles ordered by closeness to the specified width and height
*/
- // Package private visibility for testing.
- ArrayList findClosestDeviceProfiles(
- final float width, final float height, ArrayList points) {
-
- // Sort the profiles by their closeness to the dimensions
- ArrayList pointsByNearness = points;
- Collections.sort(pointsByNearness, new Comparator() {
- public int compare(InvariantDeviceProfile a, InvariantDeviceProfile b) {
- return Float.compare(dist(width, height, a.minWidthDps, a.minHeightDps),
- dist(width, height, b.minWidthDps, b.minHeightDps));
- }
- });
-
- return pointsByNearness;
+ @VisibleForTesting
+ static ArrayList sortByClosenessToSize(
+ float width, float height, ArrayList points) {
+ points.sort((a, b) ->
+ Float.compare(dist(width, height, a.minWidthDps, a.minHeightDps),
+ dist(width, height, b.minWidthDps, b.minHeightDps)));
+ return points;
}
- // Package private visibility for testing.
- InvariantDeviceProfile invDistWeightedInterpolate(float width, float height,
- ArrayList points) {
+ @VisibleForTesting
+ static DisplayOption invDistWeightedInterpolate(float width, float height,
+ ArrayList points) {
float weights = 0;
- InvariantDeviceProfile p = points.get(0);
+ DisplayOption p = points.get(0);
if (dist(width, height, p.minWidthDps, p.minHeightDps) == 0) {
return p;
}
- InvariantDeviceProfile out = new InvariantDeviceProfile();
+ DisplayOption out = new DisplayOption();
for (int i = 0; i < points.size() && i < KNEARESTNEIGHBOR; ++i) {
- p = new InvariantDeviceProfile(points.get(i));
+ p = points.get(i);
float w = weight(width, height, p.minWidthDps, p.minHeightDps, WEIGHT_POWER);
weights += w;
- out.add(p.multiply(w));
+ out.add(new DisplayOption().add(p).multiply(w));
}
- return out.multiply(1.0f/weights);
- }
-
- private void add(InvariantDeviceProfile p) {
- iconSize += p.iconSize;
- landscapeIconSize += p.landscapeIconSize;
- iconTextSize += p.iconTextSize;
- }
-
- private InvariantDeviceProfile multiply(float w) {
- iconSize *= w;
- landscapeIconSize *= w;
- iconTextSize *= w;
- return this;
+ return out.multiply(1.0f / weights);
}
public DeviceProfile getDeviceProfile(Context context) {
@@ -368,7 +351,7 @@ public class InvariantDeviceProfile {
== Configuration.ORIENTATION_LANDSCAPE ? landscapeProfile : portraitProfile;
}
- private float weight(float x0, float y0, float x1, float y1, float pow) {
+ private static float weight(float x0, float y0, float x1, float y1, float pow) {
float d = dist(x0, y0, x1, y1);
if (Float.compare(d, 0f) == 0) {
return Float.POSITIVE_INFINITY;
@@ -409,4 +392,94 @@ public class InvariantDeviceProfile {
void onIdpChanged(int changeFlags, InvariantDeviceProfile profile);
}
+
+
+ private static final class GridOption {
+
+ private final String name;
+ private final int numRows;
+ private final int numColumns;
+
+ private final int numFolderRows;
+ private final int numFolderColumns;
+
+ private final int numHotseatIcons;
+
+ private final int defaultLayoutId;
+ private final int demoModeLayoutId;
+
+ GridOption(Context context, AttributeSet attrs) {
+ TypedArray a = context.obtainStyledAttributes(
+ attrs, R.styleable.GridDisplayOption);
+ name = a.getString(R.styleable.GridDisplayOption_name);
+ numRows = a.getInt(R.styleable.GridDisplayOption_numRows, 0);
+ numColumns = a.getInt(R.styleable.GridDisplayOption_numColumns, 0);
+
+ defaultLayoutId = a.getResourceId(
+ R.styleable.GridDisplayOption_defaultLayoutId, 0);
+ demoModeLayoutId = a.getResourceId(
+ R.styleable.GridDisplayOption_demoModeLayoutId, defaultLayoutId);
+ numHotseatIcons = a.getInt(
+ R.styleable.GridDisplayOption_numHotseatIcons, numColumns);
+ numFolderRows = a.getInt(
+ R.styleable.GridDisplayOption_numFolderRows, numRows);
+ numFolderColumns = a.getInt(
+ R.styleable.GridDisplayOption_numFolderColumns, numColumns);
+ a.recycle();
+ }
+ }
+
+ private static final class DisplayOption {
+ private final GridOption grid;
+
+ private final String name;
+ private final float minWidthDps;
+ private final float minHeightDps;
+ private final boolean canBeDefault;
+
+ private float iconSize;
+ private float landscapeIconSize;
+ private float iconTextSize;
+
+ DisplayOption(GridOption grid, Context context, AttributeSet attrs) {
+ this.grid = grid;
+
+ TypedArray a = context.obtainStyledAttributes(
+ attrs, R.styleable.ProfileDisplayOption);
+
+ name = a.getString(R.styleable.ProfileDisplayOption_name);
+ minWidthDps = a.getFloat(R.styleable.ProfileDisplayOption_minWidthDps, 0);
+ minHeightDps = a.getFloat(R.styleable.ProfileDisplayOption_minHeightDps, 0);
+ canBeDefault = a.getBoolean(
+ R.styleable.ProfileDisplayOption_canBeDefault, false);
+
+ iconSize = a.getFloat(R.styleable.ProfileDisplayOption_iconSize, 0);
+ landscapeIconSize = a.getFloat(R.styleable.ProfileDisplayOption_landscapeIconSize,
+ iconSize);
+ iconTextSize = a.getFloat(R.styleable.ProfileDisplayOption_iconTextSize, 0);
+ a.recycle();
+ }
+
+ DisplayOption() {
+ grid = null;
+ name = null;
+ minWidthDps = 0;
+ minHeightDps = 0;
+ canBeDefault = false;
+ }
+
+ private DisplayOption multiply(float w) {
+ iconSize *= w;
+ landscapeIconSize *= w;
+ iconTextSize *= w;
+ return this;
+ }
+
+ private DisplayOption add(DisplayOption p) {
+ iconSize += p.iconSize;
+ landscapeIconSize += p.landscapeIconSize;
+ iconTextSize += p.iconTextSize;
+ return this;
+ }
+ }
}
\ No newline at end of file
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index b4cc1ceffc..9125a98433 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -19,6 +19,7 @@ package com.android.launcher3;
import static android.content.pm.ActivityInfo.CONFIG_LOCALE;
import static android.content.pm.ActivityInfo.CONFIG_ORIENTATION;
import static android.content.pm.ActivityInfo.CONFIG_SCREEN_SIZE;
+
import static com.android.launcher3.AbstractFloatingView.TYPE_SNACKBAR;
import static com.android.launcher3.LauncherAnimUtils.SPRING_LOADED_EXIT_DELAY;
import static com.android.launcher3.LauncherState.ALL_APPS;
@@ -26,6 +27,8 @@ import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.dragndrop.DragLayer.ALPHA_INDEX_LAUNCHER_LOAD;
import static com.android.launcher3.logging.LoggerUtils.newContainerTarget;
import static com.android.launcher3.logging.LoggerUtils.newTarget;
+import static com.android.launcher3.util.RaceConditionTracker.ENTER;
+import static com.android.launcher3.util.RaceConditionTracker.EXIT;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -71,16 +74,18 @@ import android.view.accessibility.AccessibilityEvent;
import android.view.animation.OvershootInterpolator;
import android.widget.Toast;
+import androidx.annotation.Nullable;
+
import com.android.launcher3.DropTarget.DragObject;
import com.android.launcher3.accessibility.LauncherAccessibilityDelegate;
import com.android.launcher3.allapps.AllAppsContainerView;
import com.android.launcher3.allapps.AllAppsTransitionController;
import com.android.launcher3.allapps.DiscoveryBounce;
import com.android.launcher3.anim.PropertyListBuilder;
-import com.android.launcher3.dot.DotInfo;
import com.android.launcher3.compat.AppWidgetManagerCompat;
import com.android.launcher3.compat.LauncherAppsCompatVO;
import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.dot.DotInfo;
import com.android.launcher3.dragndrop.DragController;
import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.dragndrop.DragView;
@@ -116,6 +121,7 @@ import com.android.launcher3.util.MultiValueAlpha.AlphaProperty;
import com.android.launcher3.util.PackageManagerHelper;
import com.android.launcher3.util.PackageUserKey;
import com.android.launcher3.util.PendingRequestArgs;
+import com.android.launcher3.util.RaceConditionTracker;
import com.android.launcher3.util.SystemUiController;
import com.android.launcher3.util.Themes;
import com.android.launcher3.util.Thunk;
@@ -143,8 +149,6 @@ import java.util.HashSet;
import java.util.List;
import java.util.Set;
-import androidx.annotation.Nullable;
-
/**
* Default launcher application.
*/
@@ -184,6 +188,7 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
private static final String RUNTIME_STATE_PENDING_ACTIVITY_RESULT = "launcher.activity_result";
// Type: SparseArray
private static final String RUNTIME_STATE_WIDGET_PANEL = "launcher.widget_panel";
+ public static final String ON_CREATE_EVT = "Launcher.onCreate";
private LauncherStateManager mStateManager;
@@ -255,6 +260,7 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
@Override
protected void onCreate(Bundle savedInstanceState) {
+ RaceConditionTracker.onEvent(ON_CREATE_EVT, ENTER);
if (DEBUG_STRICT_MODE) {
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
.detectDiskReads()
@@ -349,6 +355,7 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
mRotationHelper.initialize();
TraceHelper.endSection("Launcher-onCreate");
+ RaceConditionTracker.onEvent(ON_CREATE_EVT, EXIT);
}
@Override
@@ -1747,7 +1754,6 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
orderedScreenIds.indexOf(Workspace.FIRST_SCREEN_ID) != 0) {
orderedScreenIds.removeValue(Workspace.FIRST_SCREEN_ID);
orderedScreenIds.add(0, Workspace.FIRST_SCREEN_ID);
- LauncherModel.updateWorkspaceScreenOrder(this, orderedScreenIds);
} else if (!FeatureFlags.QSB_ON_FIRST_SCREEN.get()
&& orderedScreenIds.isEmpty()) {
// If there are no screens, we need to have an empty screen
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index a5f97de7ab..9b4c5fd095 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -20,12 +20,8 @@ import static com.android.launcher3.LauncherAppState.ACTION_FORCE_ROLOAD;
import static com.android.launcher3.config.FeatureFlags.IS_DOGFOOD_BUILD;
import android.content.BroadcastReceiver;
-import android.content.ContentProviderOperation;
-import android.content.ContentResolver;
-import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
-import android.net.Uri;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
@@ -38,8 +34,8 @@ import android.util.Pair;
import com.android.launcher3.compat.LauncherAppsCompat;
import com.android.launcher3.compat.PackageInstallerCompat.PackageInstallInfo;
import com.android.launcher3.compat.UserManagerCompat;
-import com.android.launcher3.icons.LauncherIcons;
import com.android.launcher3.icons.IconCache;
+import com.android.launcher3.icons.LauncherIcons;
import com.android.launcher3.model.AddWorkspaceItemsTask;
import com.android.launcher3.model.BaseModelUpdateTask;
import com.android.launcher3.model.BgDataModel;
@@ -51,7 +47,6 @@ import com.android.launcher3.model.PackageInstallStateChangedTask;
import com.android.launcher3.model.PackageUpdatedTask;
import com.android.launcher3.model.ShortcutsChangedTask;
import com.android.launcher3.model.UserLockStateChangedTask;
-import com.android.launcher3.provider.LauncherDbUtils;
import com.android.launcher3.shortcuts.DeepShortcutManager;
import com.android.launcher3.shortcuts.ShortcutInfoCompat;
import com.android.launcher3.util.ComponentKey;
@@ -70,7 +65,6 @@ import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
-import java.util.Iterator;
import java.util.List;
import java.util.concurrent.CancellationException;
import java.util.concurrent.Executor;
@@ -268,53 +262,6 @@ public class LauncherModel extends BroadcastReceiver
runOnWorkerThread(r);
}
- /**
- * Update the order of the workspace screens in the database. The array list contains
- * a list of screen ids in the order that they should appear.
- */
- public static void updateWorkspaceScreenOrder(Context context, IntArray screens) {
- final ContentResolver cr = context.getContentResolver();
- final Uri uri = LauncherSettings.WorkspaceScreens.CONTENT_URI;
-
- // Create a copy with only non-negative values
- final IntArray screensCopy = new IntArray();
- for (int i = 0; i < screens.size(); i++) {
- int id = screens.get(i);
- if (id >= 0) {
- screensCopy.add(id);
- }
- }
-
- Runnable r = new Runnable() {
- @Override
- public void run() {
- ArrayList ops = new ArrayList();
- // Clear the table
- ops.add(ContentProviderOperation.newDelete(uri).build());
- int count = screensCopy.size();
- for (int i = 0; i < count; i++) {
- ContentValues v = new ContentValues();
- int screenId = screensCopy.get(i);
- v.put(LauncherSettings.WorkspaceScreens._ID, screenId);
- v.put(LauncherSettings.WorkspaceScreens.SCREEN_RANK, i);
- ops.add(ContentProviderOperation.newInsert(uri).withValues(v).build());
- }
-
- try {
- cr.applyBatch(LauncherProvider.AUTHORITY, ops);
- } catch (Exception ex) {
- throw new RuntimeException(ex);
- }
-
- synchronized (sBgDataModel) {
- sBgDataModel.workspaceScreens.clear();
- sBgDataModel.workspaceScreens.addAll(screensCopy);
- }
- }
- };
- runOnWorkerThread(r);
- }
-
/**
* Set this as the current Launcher activity object for the loader.
*/
@@ -519,18 +466,6 @@ public class LauncherModel extends BroadcastReceiver
}
}
- /**
- * Loads the workspace screen ids in an ordered list.
- */
- public static IntArray loadWorkspaceScreensDb(Context context) {
- final ContentResolver contentResolver = context.getContentResolver();
- final Uri screensUri = LauncherSettings.WorkspaceScreens.CONTENT_URI;
-
- // Get screens ordered by rank.
- return LauncherDbUtils.getScreenIdsFromCursor(contentResolver.query(
- screensUri, null, null, null, LauncherSettings.WorkspaceScreens.SCREEN_RANK));
- }
-
public void onInstallSessionCreated(final PackageInstallInfo sessionInfo) {
enqueueModelUpdateTask(new BaseModelUpdateTask() {
@Override
diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java
index 7db3d5b9db..8ed3314efd 100644
--- a/src/com/android/launcher3/LauncherProvider.java
+++ b/src/com/android/launcher3/LauncherProvider.java
@@ -32,6 +32,7 @@ import android.content.SharedPreferences;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Resources;
import android.database.Cursor;
+import android.database.DatabaseUtils;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteQueryBuilder;
@@ -45,12 +46,12 @@ import android.os.Message;
import android.os.Process;
import android.os.UserHandle;
import android.os.UserManager;
+import android.provider.BaseColumns;
import android.text.TextUtils;
import android.util.Log;
import com.android.launcher3.AutoInstallsLayout.LayoutParserCallback;
import com.android.launcher3.LauncherSettings.Favorites;
-import com.android.launcher3.LauncherSettings.WorkspaceScreens;
import com.android.launcher3.compat.UserManagerCompat;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.logging.FileLog;
@@ -70,6 +71,7 @@ import java.io.PrintWriter;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Locale;
public class LauncherProvider extends ContentProvider {
private static final String TAG = "LauncherProvider";
@@ -79,8 +81,9 @@ public class LauncherProvider extends ContentProvider {
/**
* Represents the schema of the database. Changes in scheme need not be backwards compatible.
+ * When increasing the scheme version, ensure that downgrade_schema.json is updated
*/
- public static final int SCHEMA_VERSION = 27;
+ public static final int SCHEMA_VERSION = 28;
public static final String AUTHORITY = BuildConfig.APPLICATION_ID + ".settings";
@@ -175,10 +178,10 @@ public class LauncherProvider extends ContentProvider {
if (values == null) {
throw new RuntimeException("Error: attempting to insert null values");
}
- if (!values.containsKey(LauncherSettings.ChangeLogColumns._ID)) {
+ if (!values.containsKey(LauncherSettings.Favorites._ID)) {
throw new RuntimeException("Error: attempting to add item without specifying an id");
}
- helper.checkId(table, values);
+ helper.checkId(values);
return (int) db.insert(table, nullColumnHack, values);
}
@@ -262,24 +265,7 @@ public class LauncherProvider extends ContentProvider {
}
}
- // Add screen id if not present
- int screenId = values.getAsInteger(LauncherSettings.Favorites.SCREEN);
- SQLiteStatement stmp = null;
- try {
- stmp = mOpenHelper.getWritableDatabase().compileStatement(
- "INSERT OR IGNORE INTO workspaceScreens (_id, screenRank) " +
- "select ?, (ifnull(MAX(screenRank), -1)+1) from workspaceScreens");
- stmp.bindLong(1, screenId);
-
- ContentValues valuesInserted = new ContentValues();
- valuesInserted.put(LauncherSettings.BaseLauncherColumns._ID, stmp.executeInsert());
- mOpenHelper.checkId(WorkspaceScreens.TABLE_NAME, valuesInserted);
- return true;
- } catch (Exception e) {
- return false;
- } finally {
- Utilities.closeSilently(stmp);
- }
+ return true;
}
@Override
@@ -404,7 +390,6 @@ public class LauncherProvider extends ContentProvider {
* @return Ids of deleted folders.
*/
private IntArray deleteEmptyFolders() {
- IntArray folderIds = new IntArray();
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
try (SQLiteTransaction t = new SQLiteTransaction(db)) {
// Select folders whose id do not match any container value.
@@ -413,21 +398,19 @@ public class LauncherProvider extends ContentProvider {
+ LauncherSettings.Favorites._ID + " NOT IN (SELECT " +
LauncherSettings.Favorites.CONTAINER + " FROM "
+ Favorites.TABLE_NAME + ")";
- try (Cursor c = db.query(Favorites.TABLE_NAME,
- new String[] {LauncherSettings.Favorites._ID},
- selection, null, null, null, null)) {
- LauncherDbUtils.iterateCursor(c, 0, folderIds);
- }
+
+ IntArray folderIds = LauncherDbUtils.queryIntArray(db, Favorites.TABLE_NAME,
+ Favorites._ID, selection, null, null);
if (!folderIds.isEmpty()) {
db.delete(Favorites.TABLE_NAME, Utilities.createDbSelectionQuery(
LauncherSettings.Favorites._ID, folderIds), null);
}
t.commit();
+ return folderIds;
} catch (SQLException ex) {
Log.e(TAG, ex.getMessage(), ex);
- folderIds.clear();
+ return new IntArray();
}
- return folderIds;
}
/**
@@ -438,7 +421,7 @@ public class LauncherProvider extends ContentProvider {
}
@Thunk static void addModifiedTime(ContentValues values) {
- values.put(LauncherSettings.ChangeLogColumns.MODIFIED, System.currentTimeMillis());
+ values.put(LauncherSettings.Favorites.MODIFIED, System.currentTimeMillis());
}
private void clearFlagEmptyDbCreated() {
@@ -551,11 +534,10 @@ public class LauncherProvider extends ContentProvider {
// Table creation sometimes fails silently, which leads to a crash loop.
// This way, we will try to create a table every time after crash, so the device
// would eventually be able to recover.
- if (!tableExists(Favorites.TABLE_NAME) || !tableExists(WorkspaceScreens.TABLE_NAME)) {
+ if (!tableExists(Favorites.TABLE_NAME)) {
Log.e(TAG, "Tables are missing after onCreate has been called. Trying to recreate");
// This operation is a no-op if the table already exists.
addFavoritesTable(getWritableDatabase(), true);
- addWorkspacesTable(getWritableDatabase(), true);
}
initIds();
@@ -602,7 +584,6 @@ public class LauncherProvider extends ContentProvider {
mMaxScreenId = 0;
addFavoritesTable(db, false);
- addWorkspacesTable(db, false);
// Fresh and clean launcher DB.
mMaxItemId = initializeMaxItemId(db);
@@ -633,46 +614,6 @@ public class LauncherProvider extends ContentProvider {
Favorites.addTableToDb(db, getDefaultUserSerial(), optional);
}
- private void addWorkspacesTable(SQLiteDatabase db, boolean optional) {
- String ifNotExists = optional ? " IF NOT EXISTS " : "";
- db.execSQL("CREATE TABLE " + ifNotExists + WorkspaceScreens.TABLE_NAME + " (" +
- LauncherSettings.WorkspaceScreens._ID + " INTEGER PRIMARY KEY," +
- LauncherSettings.WorkspaceScreens.SCREEN_RANK + " INTEGER," +
- LauncherSettings.ChangeLogColumns.MODIFIED + " INTEGER NOT NULL DEFAULT 0" +
- ");");
- }
-
- private void removeOrphanedItems(SQLiteDatabase db) {
- // Delete items directly on the workspace who's screen id doesn't exist
- // "DELETE FROM favorites WHERE screen NOT IN (SELECT _id FROM workspaceScreens)
- // AND container = -100"
- String removeOrphanedDesktopItems = "DELETE FROM " + Favorites.TABLE_NAME +
- " WHERE " +
- LauncherSettings.Favorites.SCREEN + " NOT IN (SELECT " +
- LauncherSettings.WorkspaceScreens._ID + " FROM " + WorkspaceScreens.TABLE_NAME + ")" +
- " AND " +
- LauncherSettings.Favorites.CONTAINER + " = " +
- LauncherSettings.Favorites.CONTAINER_DESKTOP;
- db.execSQL(removeOrphanedDesktopItems);
-
- // Delete items contained in folders which no longer exist (after above statement)
- // "DELETE FROM favorites WHERE container <> -100 AND container <> -101 AND container
- // NOT IN (SELECT _id FROM favorites WHERE itemType = 2)"
- String removeOrphanedFolderItems = "DELETE FROM " + Favorites.TABLE_NAME +
- " WHERE " +
- LauncherSettings.Favorites.CONTAINER + " <> " +
- LauncherSettings.Favorites.CONTAINER_DESKTOP +
- " AND "
- + LauncherSettings.Favorites.CONTAINER + " <> " +
- LauncherSettings.Favorites.CONTAINER_HOTSEAT +
- " AND "
- + LauncherSettings.Favorites.CONTAINER + " NOT IN (SELECT " +
- LauncherSettings.Favorites._ID + " FROM " + Favorites.TABLE_NAME +
- " WHERE " + LauncherSettings.Favorites.ITEM_TYPE + " = " +
- LauncherSettings.Favorites.ITEM_TYPE_FOLDER + ")";
- db.execSQL(removeOrphanedFolderItems);
- }
-
@Override
public void onOpen(SQLiteDatabase db) {
super.onOpen(db);
@@ -681,8 +622,7 @@ public class LauncherProvider extends ContentProvider {
if (!schemaFile.exists()) {
handleOneTimeDataUpgrade(db);
}
- DbDowngradeHelper.updateSchemaFile(schemaFile, SCHEMA_VERSION, mContext,
- R.raw.downgrade_schema);
+ DbDowngradeHelper.updateSchemaFile(schemaFile, SCHEMA_VERSION, mContext);
}
/**
@@ -709,12 +649,8 @@ public class LauncherProvider extends ContentProvider {
switch (oldVersion) {
// The version cannot be lower that 12, as Launcher3 never supported a lower
// version of the DB.
- case 12: {
- // With the new shrink-wrapped and re-orderable workspaces, it makes sense
- // to persist workspace screens and their relative order.
- mMaxScreenId = 0;
- addWorkspacesTable(db, false);
- }
+ case 12:
+ // No-op
case 13: {
try (SQLiteTransaction t = new SQLiteTransaction(db)) {
// Insert new column for holding widget provider name
@@ -728,15 +664,7 @@ public class LauncherProvider extends ContentProvider {
}
}
case 14: {
- try (SQLiteTransaction t = new SQLiteTransaction(db)) {
- // Insert new column for holding update timestamp
- db.execSQL("ALTER TABLE favorites " +
- "ADD COLUMN modified INTEGER NOT NULL DEFAULT 0;");
- db.execSQL("ALTER TABLE workspaceScreens " +
- "ADD COLUMN modified INTEGER NOT NULL DEFAULT 0;");
- t.commit();
- } catch (SQLException ex) {
- Log.e(TAG, ex.getMessage(), ex);
+ if (!addIntegerColumn(db, Favorites.MODIFIED, 0)) {
// Old version remains, which means we wipe old data
break;
}
@@ -747,22 +675,15 @@ public class LauncherProvider extends ContentProvider {
break;
}
}
- case 16: {
+ case 16:
// No-op
- }
- case 17: {
+ case 17:
+ // No-op
+ case 18:
// No-op
- }
- case 18: {
- // Due to a data loss bug, some users may have items associated with screen ids
- // which no longer exist. Since this can cause other problems, and since the user
- // will never see these items anyway, we use database upgrade as an opportunity to
- // clean things up.
- removeOrphanedItems(db);
- }
case 19: {
// Add userId column
- if (!addProfileColumn(db)) {
+ if (!addIntegerColumn(db, Favorites.PROFILE_ID, getDefaultUserSerial())) {
// Old version remains, which means we wipe old data
break;
}
@@ -772,10 +693,7 @@ public class LauncherProvider extends ContentProvider {
break;
}
case 21:
- // Recreate workspace table with screen id a primary key
- if (!recreateWorkspaceTable(db)) {
- break;
- }
+ // No-op
case 22: {
if (!addIntegerColumn(db, Favorites.OPTIONS, 0)) {
// Old version remains, which means we wipe old data
@@ -794,7 +712,30 @@ public class LauncherProvider extends ContentProvider {
!LauncherDbUtils.prepareScreenZeroToHostQsb(mContext, db)) {
break;
}
- case 27:
+ case 27: {
+ // Update the favorites table so that the screen ids are ordered based on
+ // workspace page rank.
+ IntArray finalScreens = LauncherDbUtils.queryIntArray(db, "workspaceScreens",
+ BaseColumns._ID, null, null, "screenRank");
+ int[] original = finalScreens.toArray();
+ Arrays.sort(original);
+ String updatemap = "";
+ for (int i = 0; i < original.length; i++) {
+ if (finalScreens.get(i) != original[i]) {
+ updatemap += String.format(Locale.ENGLISH, " WHEN %1$s=%2$d THEN %3$d",
+ Favorites.SCREEN, finalScreens.get(i), original[i]);
+ }
+ }
+ if (!TextUtils.isEmpty(updatemap)) {
+ String query = String.format(Locale.ENGLISH,
+ "UPDATE %1$s SET %2$s=CASE %3$s ELSE %2$s END WHERE %4$s = %5$d",
+ Favorites.TABLE_NAME, Favorites.SCREEN, updatemap,
+ Favorites.CONTAINER, Favorites.CONTAINER_DESKTOP);
+ db.execSQL(query);
+ }
+ db.execSQL("DROP TABLE IF EXISTS workspaceScreens");
+ }
+ case 28:
// DB Upgraded successfully
return;
}
@@ -822,7 +763,7 @@ public class LauncherProvider extends ContentProvider {
public void createEmptyDB(SQLiteDatabase db) {
try (SQLiteTransaction t = new SQLiteTransaction(db)) {
db.execSQL("DROP TABLE IF EXISTS " + Favorites.TABLE_NAME);
- db.execSQL("DROP TABLE IF EXISTS " + WorkspaceScreens.TABLE_NAME);
+ db.execSQL("DROP TABLE IF EXISTS workspaceScreens");
onCreate(db);
t.commit();
}
@@ -845,17 +786,9 @@ public class LauncherProvider extends ContentProvider {
Log.e(TAG, "getAppWidgetIds not supported", e);
return;
}
- final IntSet validWidgets = new IntSet();
- try (Cursor c = db.query(Favorites.TABLE_NAME,
- new String[] {Favorites.APPWIDGET_ID },
- "itemType=" + Favorites.ITEM_TYPE_APPWIDGET, null, null, null, null)) {
- while (c.moveToNext()) {
- validWidgets.add(c.getInt(0));
- }
- } catch (SQLException ex) {
- Log.w(TAG, "Error getting widgets list", ex);
- return;
- }
+ final IntSet validWidgets = IntSet.wrap(LauncherDbUtils.queryIntArray(db,
+ Favorites.TABLE_NAME, Favorites.APPWIDGET_ID,
+ "itemType=" + Favorites.ITEM_TYPE_APPWIDGET, null, null));
for (int widgetId : allWidgets) {
if (!validWidgets.contains(widgetId)) {
try {
@@ -910,46 +843,6 @@ public class LauncherProvider extends ContentProvider {
}
}
- /**
- * Recreates workspace table and migrates data to the new table.
- */
- public boolean recreateWorkspaceTable(SQLiteDatabase db) {
- try (SQLiteTransaction t = new SQLiteTransaction(db)) {
- final IntArray sortedIDs;
-
- try (Cursor c = db.query(WorkspaceScreens.TABLE_NAME,
- new String[] {LauncherSettings.WorkspaceScreens._ID},
- null, null, null, null,
- LauncherSettings.WorkspaceScreens.SCREEN_RANK)) {
- // Use LinkedHashSet so that ordering is preserved
- sortedIDs = LauncherDbUtils.getScreenIdsFromCursor(c);
- }
- db.execSQL("DROP TABLE IF EXISTS " + WorkspaceScreens.TABLE_NAME);
- addWorkspacesTable(db, false);
-
- // Add all screen ids back
- int total = sortedIDs.size();
- for (int i = 0; i < total; i++) {
- ContentValues values = new ContentValues();
- values.put(LauncherSettings.WorkspaceScreens._ID, sortedIDs.get(i));
- values.put(LauncherSettings.WorkspaceScreens.SCREEN_RANK, i);
- addModifiedTime(values);
- db.insertOrThrow(WorkspaceScreens.TABLE_NAME, null, values);
- }
- t.commit();
-
- mMaxScreenId = 0;
- for (int i = 0; i < sortedIDs.size(); i++) {
- mMaxScreenId = Math.max(mMaxScreenId, sortedIDs.get(i));
- }
- } catch (SQLException ex) {
- // Old version remains, which means we wipe old data
- Log.e(TAG, ex.getMessage(), ex);
- return false;
- }
- return true;
- }
-
@Thunk boolean updateFolderItemsRank(SQLiteDatabase db, boolean addRankColumn) {
try (SQLiteTransaction t = new SQLiteTransaction(db)) {
if (addRankColumn) {
@@ -979,10 +872,6 @@ public class LauncherProvider extends ContentProvider {
return true;
}
- private boolean addProfileColumn(SQLiteDatabase db) {
- return addIntegerColumn(db, Favorites.PROFILE_ID, getDefaultUserSerial());
- }
-
private boolean addIntegerColumn(SQLiteDatabase db, String columnName, long defaultValue) {
try (SQLiteTransaction t = new SQLiteTransaction(db)) {
db.execSQL("ALTER TABLE favorites ADD COLUMN "
@@ -1018,17 +907,20 @@ public class LauncherProvider extends ContentProvider {
return dbInsertAndCheck(this, db, Favorites.TABLE_NAME, null, values);
}
- public void checkId(String table, ContentValues values) {
- int id = values.getAsInteger(LauncherSettings.BaseLauncherColumns._ID);
- if (WorkspaceScreens.TABLE_NAME.equals(table)) {
- mMaxScreenId = Math.max(id, mMaxScreenId);
- } else {
- mMaxItemId = Math.max(id, mMaxItemId);
+ public void checkId(ContentValues values) {
+ int id = values.getAsInteger(Favorites._ID);
+ mMaxItemId = Math.max(id, mMaxItemId);
+
+ Integer screen = values.getAsInteger(Favorites.SCREEN);
+ Integer container = values.getAsInteger(Favorites.CONTAINER);
+ if (screen != null && container != null
+ && container.intValue() == Favorites.CONTAINER_DESKTOP) {
+ mMaxScreenId = Math.max(screen, mMaxScreenId);
}
}
private int initializeMaxItemId(SQLiteDatabase db) {
- return getMaxId(db, Favorites.TABLE_NAME);
+ return getMaxId(db, "SELECT MAX(%1$s) FROM %2$s", Favorites._ID, Favorites.TABLE_NAME);
}
// Generates a new ID to use for an workspace screen in your database. This method
@@ -1045,34 +937,18 @@ public class LauncherProvider extends ContentProvider {
}
private int initializeMaxScreenId(SQLiteDatabase db) {
- return getMaxId(db, WorkspaceScreens.TABLE_NAME);
+ return getMaxId(db, "SELECT MAX(%1$s) FROM %2$s WHERE %3$s = %4$d",
+ Favorites.SCREEN, Favorites.TABLE_NAME, Favorites.CONTAINER,
+ Favorites.CONTAINER_DESKTOP);
}
@Thunk int loadFavorites(SQLiteDatabase db, AutoInstallsLayout loader) {
- IntArray screenIds = new IntArray();
// TODO: Use multiple loaders with fall-back and transaction.
- int count = loader.loadLayout(db, screenIds);
-
- // Add the screens specified by the items above
- int[] sortedScreenIds = screenIds.toArray();
- Arrays.sort(sortedScreenIds);
- int rank = 0;
- ContentValues values = new ContentValues();
- for (int id : sortedScreenIds) {
- values.clear();
- values.put(LauncherSettings.WorkspaceScreens._ID, id);
- values.put(LauncherSettings.WorkspaceScreens.SCREEN_RANK, rank);
- if (dbInsertAndCheck(this, db, WorkspaceScreens.TABLE_NAME, null, values) < 0) {
- throw new RuntimeException("Failed initialize screen table"
- + "from default layout");
- }
- rank++;
- }
+ int count = loader.loadLayout(db, new IntArray());
// Ensure that the max ids are initialized
mMaxItemId = initializeMaxItemId(db);
mMaxScreenId = initializeMaxScreenId(db);
-
return count;
}
}
@@ -1080,22 +956,14 @@ public class LauncherProvider extends ContentProvider {
/**
* @return the max _id in the provided table.
*/
- @Thunk static int getMaxId(SQLiteDatabase db, String table) {
- Cursor c = db.rawQuery("SELECT MAX(_id) FROM " + table, null);
- // get the result
- int id = -1;
- if (c != null && c.moveToNext()) {
- id = c.getInt(0);
+ @Thunk static int getMaxId(SQLiteDatabase db, String query, Object... args) {
+ int max = (int) DatabaseUtils.longForQuery(db,
+ String.format(Locale.ENGLISH, query, args),
+ null);
+ if (max < 0) {
+ throw new RuntimeException("Error: could not query max id");
}
- if (c != null) {
- c.close();
- }
-
- if (id == -1) {
- throw new RuntimeException("Error: could not query max id in " + table);
- }
-
- return id;
+ return max;
}
static class SqlArguments {
diff --git a/src/com/android/launcher3/LauncherSettings.java b/src/com/android/launcher3/LauncherSettings.java
index 0b12b15f9e..79c8208736 100644
--- a/src/com/android/launcher3/LauncherSettings.java
+++ b/src/com/android/launcher3/LauncherSettings.java
@@ -26,16 +26,17 @@ import android.provider.BaseColumns;
* Settings related utilities.
*/
public class LauncherSettings {
- /** Columns required on table staht will be subject to backup and restore. */
- static interface ChangeLogColumns extends BaseColumns {
+
+ /**
+ * Favorites.
+ */
+ public static final class Favorites implements BaseColumns {
/**
* The time of the last update to this row.
* Type: INTEGER
*/
public static final String MODIFIED = "modified";
- }
- static public interface BaseLauncherColumns extends ChangeLogColumns {
/**
* Descriptive name of the gesture that can be displayed to the user.
* Type: TEXT
@@ -84,34 +85,6 @@ public class LauncherSettings {
* Type: BLOB
*/
public static final String ICON = "icon";
- }
-
- /**
- * Workspace Screens.
- *
- * Tracks the order of workspace screens.
- */
- public static final class WorkspaceScreens implements ChangeLogColumns {
-
- public static final String TABLE_NAME = "workspaceScreens";
-
- /**
- * The content:// style URL for this table
- */
- public static final Uri CONTENT_URI = Uri.parse("content://" +
- LauncherProvider.AUTHORITY + "/" + TABLE_NAME);
-
- /**
- * The rank of this screen -- ie. how it is ordered relative to the other screens.
- * Type: INTEGER
- */
- public static final String SCREEN_RANK = "screenRank";
- }
-
- /**
- * Favorites.
- */
- public static final class Favorites implements BaseLauncherColumns {
public static final String TABLE_NAME = "favorites";
diff --git a/src/com/android/launcher3/MainProcessInitializer.java b/src/com/android/launcher3/MainProcessInitializer.java
index a2538930e1..9692d73b23 100644
--- a/src/com/android/launcher3/MainProcessInitializer.java
+++ b/src/com/android/launcher3/MainProcessInitializer.java
@@ -20,7 +20,6 @@ import android.content.Context;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.folder.FolderShape;
-import com.android.launcher3.graphics.IconShapeOverride;
import com.android.launcher3.logging.FileLog;
import com.android.launcher3.util.ResourceBasedOverride;
@@ -38,7 +37,6 @@ public class MainProcessInitializer implements ResourceBasedOverride {
protected void init(Context context) {
FileLog.setDir(context.getApplicationContext().getFilesDir());
FeatureFlags.initialize(context);
- IconShapeOverride.apply(context);
SessionCommitReceiver.applyDefaultUserPrefs(context);
FolderShape.init();
}
diff --git a/src/com/android/launcher3/SecondaryDropTarget.java b/src/com/android/launcher3/SecondaryDropTarget.java
index 6083415d52..0cf6e44c63 100644
--- a/src/com/android/launcher3/SecondaryDropTarget.java
+++ b/src/com/android/launcher3/SecondaryDropTarget.java
@@ -150,7 +150,7 @@ public class SecondaryDropTarget extends ButtonDropTarget implements OnAlarmList
Intent intent = null;
UserHandle user = null;
if (item != null &&
- item.itemType == LauncherSettings.BaseLauncherColumns.ITEM_TYPE_APPLICATION) {
+ item.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {
intent = item.getIntent();
user = item.user;
}
diff --git a/src/com/android/launcher3/ShortcutInfo.java b/src/com/android/launcher3/ShortcutInfo.java
index 19c647fd74..c2c3287458 100644
--- a/src/com/android/launcher3/ShortcutInfo.java
+++ b/src/com/android/launcher3/ShortcutInfo.java
@@ -89,7 +89,7 @@ public class ShortcutInfo extends ItemInfoWithIcon {
private int mInstallProgress;
public ShortcutInfo() {
- itemType = LauncherSettings.BaseLauncherColumns.ITEM_TYPE_SHORTCUT;
+ itemType = LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT;
}
public ShortcutInfo(ShortcutInfo info) {
@@ -114,24 +114,23 @@ public class ShortcutInfo extends ItemInfoWithIcon {
@TargetApi(Build.VERSION_CODES.N)
public ShortcutInfo(ShortcutInfoCompat shortcutInfo, Context context) {
user = shortcutInfo.getUserHandle();
- itemType = LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT;
+ itemType = Favorites.ITEM_TYPE_DEEP_SHORTCUT;
updateFromDeepShortcutInfo(shortcutInfo, context);
}
@Override
public void onAddToDatabase(ContentWriter writer) {
super.onAddToDatabase(writer);
- writer.put(LauncherSettings.BaseLauncherColumns.TITLE, title)
- .put(LauncherSettings.BaseLauncherColumns.INTENT, getIntent())
- .put(LauncherSettings.Favorites.RESTORED, status);
+ writer.put(Favorites.TITLE, title)
+ .put(Favorites.INTENT, getIntent())
+ .put(Favorites.RESTORED, status);
if (!usingLowResIcon()) {
writer.putIcon(iconBitmap, user);
}
if (iconResource != null) {
- writer.put(LauncherSettings.BaseLauncherColumns.ICON_PACKAGE, iconResource.packageName)
- .put(LauncherSettings.BaseLauncherColumns.ICON_RESOURCE,
- iconResource.resourceName);
+ writer.put(Favorites.ICON_PACKAGE, iconResource.packageName)
+ .put(Favorites.ICON_RESOURCE, iconResource.resourceName);
}
}
@@ -189,7 +188,7 @@ public class ShortcutInfo extends ItemInfoWithIcon {
@Override
public ComponentName getTargetComponent() {
ComponentName cn = super.getTargetComponent();
- if (cn == null && (itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT
+ if (cn == null && (itemType == Favorites.ITEM_TYPE_SHORTCUT
|| hasStatusFlag(FLAG_SUPPORTS_WEB_UI))) {
// Legacy shortcuts and promise icons with web UI may not have a componentName but just
// a packageName. In that case create a dummy componentName instead of adding additional
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index 65f0703278..a0f005c432 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -31,6 +31,7 @@ import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.graphics.Paint;
+import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.RectF;
import android.os.Build;
@@ -587,6 +588,21 @@ public final class Utilities {
handler.sendMessage(msg);
}
+ /**
+ * Parses a string encoded using {@link #getPointString(int, int)}
+ */
+ public static Point parsePoint(String point) {
+ String[] split = point.split(",");
+ return new Point(Integer.parseInt(split[0]), Integer.parseInt(split[1]));
+ }
+
+ /**
+ * Encodes a point to string to that it can be persisted atomically.
+ */
+ public static String getPointString(int x, int y) {
+ return String.format(Locale.ENGLISH, "%d,%d", x, y);
+ }
+
public interface Consumer {
void accept(T var1);
}
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 47ebb17952..eb26961c32 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -619,9 +619,6 @@ public class Workspace extends PagedView
// if this is the last screen, convert it to the empty screen
mWorkspaceScreens.put(EXTRA_EMPTY_SCREEN_ID, finalScreen);
mScreenOrder.add(EXTRA_EMPTY_SCREEN_ID);
-
- // Update the model if we have changed any screens
- LauncherModel.updateWorkspaceScreenOrder(mLauncher, mScreenOrder);
}
}
@@ -728,9 +725,6 @@ public class Workspace extends PagedView
mWorkspaceScreens.put(newId, cl);
mScreenOrder.add(newId);
- // Update the model for the new screen
- LauncherModel.updateWorkspaceScreenOrder(mLauncher, mScreenOrder);
-
return newId;
}
@@ -828,13 +822,6 @@ public class Workspace extends PagedView
}
}
- if (!removeScreens.isEmpty()) {
- // Update the model if we have changed any screens
- mLauncher.getModelWriter().enqueueDeleteRunnable(
- () -> LauncherModel.updateWorkspaceScreenOrder(mLauncher, mScreenOrder));
-
- }
-
if (pageShift >= 0) {
setCurrentPage(currentPage - pageShift);
}
@@ -3078,9 +3065,9 @@ public class Workspace extends PagedView
mapOverItems(MAP_RECURSE, new ItemOperator() {
@Override
public boolean evaluate(ItemInfo info, View v) {
- if (info instanceof ShortcutInfo && v instanceof BubbleTextView
- && packageUserKey.updateFromItemInfo(info)) {
- if (updatedDots.contains(packageUserKey)) {
+ if (info instanceof ShortcutInfo && v instanceof BubbleTextView) {
+ if (!packageUserKey.updateFromItemInfo(info)
+ || updatedDots.contains(packageUserKey)) {
((BubbleTextView) v).applyDotState(info, true /* animate */);
folderIds.add(info.container);
}
diff --git a/src/com/android/launcher3/graphics/IconShapeOverride.java b/src/com/android/launcher3/graphics/IconShapeOverride.java
deleted file mode 100644
index b636c6d478..0000000000
--- a/src/com/android/launcher3/graphics/IconShapeOverride.java
+++ /dev/null
@@ -1,214 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.launcher3.graphics;
-
-import static com.android.launcher3.Utilities.getDevicePrefs;
-
-import android.annotation.TargetApi;
-import android.app.AlarmManager;
-import android.app.PendingIntent;
-import android.app.ProgressDialog;
-import android.content.Context;
-import android.content.Intent;
-import android.content.res.Resources;
-import android.os.Build;
-import android.os.SystemClock;
-import android.provider.Settings;
-import android.text.TextUtils;
-import android.util.Log;
-
-import com.android.launcher3.LauncherAppState;
-import com.android.launcher3.LauncherModel;
-import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
-import com.android.launcher3.util.LooperExecutor;
-
-import java.lang.reflect.Field;
-
-import androidx.annotation.NonNull;
-import androidx.preference.ListPreference;
-import androidx.preference.Preference;
-import androidx.preference.Preference.OnPreferenceChangeListener;
-
-/**
- * Utility class to override shape of {@link android.graphics.drawable.AdaptiveIconDrawable}.
- */
-@TargetApi(Build.VERSION_CODES.O)
-public class IconShapeOverride {
-
- private static final String TAG = "IconShapeOverride";
-
- public static final String KEY_PREFERENCE = "pref_override_icon_shape";
-
- // Time to wait before killing the process this ensures that the progress bar is visible for
- // sufficient time so that there is no flicker.
- private static final long PROCESS_KILL_DELAY_MS = 1000;
-
- private static final int RESTART_REQUEST_CODE = 42; // the answer to everything
-
- public static boolean isSupported(Context context) {
- if (!Utilities.ATLEAST_OREO) {
- return false;
- }
- // Only supported when developer settings is enabled
- if (Settings.Global.getInt(context.getContentResolver(),
- Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 0) != 1) {
- return false;
- }
-
- try {
- if (getSystemResField().get(null) != Resources.getSystem()) {
- // Our assumption that mSystem is the system resource is not true.
- return false;
- }
- } catch (Exception e) {
- // Ignore, not supported
- return false;
- }
-
- return getConfigResId() != 0;
- }
-
- public static void apply(Context context) {
- if (!Utilities.ATLEAST_OREO) {
- return;
- }
- String path = getAppliedValue(context);
- if (TextUtils.isEmpty(path)) {
- return;
- }
- if (!isSupported(context)) {
- return;
- }
-
- // magic
- try {
- Resources override =
- new ResourcesOverride(Resources.getSystem(), getConfigResId(), path);
- getSystemResField().set(null, override);
- } catch (Exception e) {
- Log.e(TAG, "Unable to override icon shape", e);
- // revert value.
- getDevicePrefs(context).edit().remove(KEY_PREFERENCE).apply();
- }
- }
-
- private static Field getSystemResField() throws Exception {
- Field staticField = Resources.class.getDeclaredField("mSystem");
- staticField.setAccessible(true);
- return staticField;
- }
-
- private static int getConfigResId() {
- return Resources.getSystem().getIdentifier("config_icon_mask", "string", "android");
- }
-
- private static String getAppliedValue(Context context) {
- return getDevicePrefs(context).getString(KEY_PREFERENCE, "");
- }
-
- public static void handlePreferenceUi(ListPreference preference) {
- Context context = preference.getContext();
- preference.setValue(getAppliedValue(context));
- preference.setOnPreferenceChangeListener(new PreferenceChangeHandler(context));
- }
-
- private static class ResourcesOverride extends Resources {
-
- private final int mOverrideId;
- private final String mOverrideValue;
-
- @SuppressWarnings("deprecation")
- public ResourcesOverride(Resources parent, int overrideId, String overrideValue) {
- super(parent.getAssets(), parent.getDisplayMetrics(), parent.getConfiguration());
- mOverrideId = overrideId;
- mOverrideValue = overrideValue;
- }
-
- @NonNull
- @Override
- public String getString(int id) throws NotFoundException {
- if (id == mOverrideId) {
- return mOverrideValue;
- }
- return super.getString(id);
- }
- }
-
- private static class PreferenceChangeHandler implements OnPreferenceChangeListener {
-
- private final Context mContext;
-
- private PreferenceChangeHandler(Context context) {
- mContext = context;
- }
-
- @Override
- public boolean onPreferenceChange(Preference preference, Object o) {
- String newValue = (String) o;
- if (!getAppliedValue(mContext).equals(newValue)) {
- // Value has changed
- ProgressDialog.show(mContext,
- null /* title */,
- mContext.getString(R.string.icon_shape_override_progress),
- true /* indeterminate */,
- false /* cancelable */);
- new LooperExecutor(LauncherModel.getWorkerLooper()).execute(
- new OverrideApplyHandler(mContext, newValue));
- }
- return false;
- }
- }
-
- private static class OverrideApplyHandler implements Runnable {
-
- private final Context mContext;
- private final String mValue;
-
- private OverrideApplyHandler(Context context, String value) {
- mContext = context;
- mValue = value;
- }
-
- @Override
- public void run() {
- // Synchronously write the preference.
- getDevicePrefs(mContext).edit().putString(KEY_PREFERENCE, mValue).commit();
- // Clear the icon cache.
- LauncherAppState.getInstance(mContext).getIconCache().clear();
-
- // Wait for it
- try {
- Thread.sleep(PROCESS_KILL_DELAY_MS);
- } catch (Exception e) {
- Log.e(TAG, "Error waiting", e);
- }
-
- // Schedule an alarm before we kill ourself.
- Intent homeIntent = new Intent(Intent.ACTION_MAIN)
- .addCategory(Intent.CATEGORY_HOME)
- .setPackage(mContext.getPackageName())
- .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- PendingIntent pi = PendingIntent.getActivity(mContext, RESTART_REQUEST_CODE,
- homeIntent, PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT);
- mContext.getSystemService(AlarmManager.class).setExact(
- AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime() + 50, pi);
-
- // Kill process
- android.os.Process.killProcess(android.os.Process.myPid());
- }
- }
-}
diff --git a/src/com/android/launcher3/model/AddWorkspaceItemsTask.java b/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
index 756d44e814..5fc555172f 100644
--- a/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
+++ b/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
@@ -15,11 +15,11 @@
*/
package com.android.launcher3.model;
-import android.content.Context;
import android.content.Intent;
import android.os.UserHandle;
import android.util.LongSparseArray;
import android.util.Pair;
+
import com.android.launcher3.AllAppsList;
import com.android.launcher3.AppInfo;
import com.android.launcher3.FolderInfo;
@@ -27,7 +27,6 @@ import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.ItemInfo;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherAppWidgetInfo;
-import com.android.launcher3.LauncherModel;
import com.android.launcher3.LauncherModel.CallbackTask;
import com.android.launcher3.LauncherModel.Callbacks;
import com.android.launcher3.LauncherSettings;
@@ -58,16 +57,12 @@ public class AddWorkspaceItemsTask extends BaseModelUpdateTask {
if (mItemList.isEmpty()) {
return;
}
- Context context = app.getContext();
final ArrayList addedItemsFinal = new ArrayList<>();
final IntArray addedWorkspaceScreensFinal = new IntArray();
- // Get the list of workspace screens. We need to append to this list and
- // can not use sBgWorkspaceScreens because loadWorkspace() may not have been
- // called.
- IntArray workspaceScreens = LauncherModel.loadWorkspaceScreensDb(context);
synchronized(dataModel) {
+ IntArray workspaceScreens = dataModel.workspaceScreens.clone();
List filteredItems = new ArrayList<>();
for (Pair entry : mItemList) {
@@ -116,9 +111,6 @@ public class AddWorkspaceItemsTask extends BaseModelUpdateTask {
}
}
- // Update the workspace screens
- updateScreens(context, workspaceScreens);
-
if (!addedItemsFinal.isEmpty()) {
scheduleCallbackTask(new CallbackTask() {
@Override
@@ -143,10 +135,6 @@ public class AddWorkspaceItemsTask extends BaseModelUpdateTask {
}
}
- protected void updateScreens(Context context, IntArray workspaceScreens) {
- LauncherModel.updateWorkspaceScreenOrder(context, workspaceScreens);
- }
-
/**
* Returns true if the shortcuts already exists on the workspace. This must be called after
* the workspace has been loaded. We identify a shortcut by its intent.
diff --git a/src/com/android/launcher3/model/DbDowngradeHelper.java b/src/com/android/launcher3/model/DbDowngradeHelper.java
index cd86b728b1..e5c44d1aad 100644
--- a/src/com/android/launcher3/model/DbDowngradeHelper.java
+++ b/src/com/android/launcher3/model/DbDowngradeHelper.java
@@ -21,6 +21,7 @@ import android.database.sqlite.SQLiteException;
import android.util.Log;
import android.util.SparseArray;
+import com.android.launcher3.R;
import com.android.launcher3.provider.LauncherDbUtils.SQLiteTransaction;
import com.android.launcher3.util.IOUtils;
@@ -87,8 +88,7 @@ public class DbDowngradeHelper {
return helper;
}
- public static void updateSchemaFile(File schemaFile, int expectedVersion,
- Context context, int schemaResId) {
+ public static void updateSchemaFile(File schemaFile, int expectedVersion, Context context) {
try {
if (DbDowngradeHelper.parse(schemaFile).version >= expectedVersion) {
return;
@@ -99,7 +99,7 @@ public class DbDowngradeHelper {
// Write the updated schema
try (FileOutputStream fos = new FileOutputStream(schemaFile);
- InputStream in = context.getResources().openRawResource(schemaResId)) {
+ InputStream in = context.getResources().openRawResource(R.raw.downgrade_schema)) {
IOUtils.copy(in, fos);
} catch (IOException e) {
Log.e(TAG, "Error writing schema file", e);
diff --git a/src/com/android/launcher3/model/GridSizeMigrationTask.java b/src/com/android/launcher3/model/GridSizeMigrationTask.java
index 2c1aa745f0..a9ddccb670 100644
--- a/src/com/android/launcher3/model/GridSizeMigrationTask.java
+++ b/src/com/android/launcher3/model/GridSizeMigrationTask.java
@@ -1,5 +1,8 @@
package com.android.launcher3.model;
+import static com.android.launcher3.Utilities.getPointString;
+import static com.android.launcher3.Utilities.parsePoint;
+
import android.content.ComponentName;
import android.content.ContentProviderOperation;
import android.content.ContentValues;
@@ -10,14 +13,12 @@ import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.graphics.Point;
-import android.net.Uri;
import android.util.Log;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.ItemInfo;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherAppWidgetProviderInfo;
-import com.android.launcher3.LauncherModel;
import com.android.launcher3.LauncherProvider;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.LauncherSettings.Favorites;
@@ -28,12 +29,14 @@ import com.android.launcher3.compat.PackageInstallerCompat;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.util.GridOccupancy;
import com.android.launcher3.util.IntArray;
+import com.android.launcher3.util.IntSet;
import com.android.launcher3.util.IntSparseArrayMap;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
-import java.util.Locale;
+
+import androidx.annotation.VisibleForTesting;
/**
* This class takes care of shrinking the workspace (by maximum of one row and one column), as a
@@ -177,11 +180,25 @@ public class GridSizeMigrationTask {
return applyOperations();
}
+ @VisibleForTesting
+ static IntArray getWorkspaceScreenIds(Context context) {
+ IntSet set = new IntSet();
+ try (Cursor c = context.getContentResolver().query(Favorites.CONTENT_URI,
+ new String[] {Favorites.SCREEN},
+ Favorites.CONTAINER + " = " + Favorites.CONTAINER_DESKTOP,
+ null, Favorites.SCREEN)) {
+ while (c.moveToNext()) {
+ set.add(c.getInt(0));
+ }
+ }
+ return set.getArray();
+ }
+
/**
* @return true if any DB change was made
*/
protected boolean migrateWorkspace() throws Exception {
- IntArray allScreens = LauncherModel.loadWorkspaceScreensDb(mContext);
+ IntArray allScreens = getWorkspaceScreenIds(mContext);
if (allScreens.isEmpty()) {
throw new Exception("Unable to get workspace screens");
}
@@ -213,9 +230,8 @@ public class GridSizeMigrationTask {
int newScreenId = LauncherSettings.Settings.call(
mContext.getContentResolver(),
LauncherSettings.Settings.METHOD_NEW_SCREEN_ID)
- .getInt(LauncherSettings.Settings.EXTRA_VALUE);
+ .getInt(LauncherSettings.Settings.EXTRA_VALUE);
- allScreens.add(newScreenId);
for (DbEntry item : placement.finalPlacedItems) {
if (!mCarryOver.remove(itemMap.get(item.id))) {
throw new Exception("Unable to find matching items");
@@ -228,19 +244,6 @@ public class GridSizeMigrationTask {
}
} while (!mCarryOver.isEmpty());
-
- // Update screens
- final Uri uri = LauncherSettings.WorkspaceScreens.CONTENT_URI;
- mUpdateOperations.add(ContentProviderOperation.newDelete(uri).build());
- int count = allScreens.size();
- for (int i = 0; i < count; i++) {
- ContentValues v = new ContentValues();
- int screenId = allScreens.get(i);
- v.put(LauncherSettings.WorkspaceScreens._ID, screenId);
- v.put(LauncherSettings.WorkspaceScreens.SCREEN_RANK, i);
- mUpdateOperations.add(ContentProviderOperation.newInsert(uri).withValues(
- v).build());
- }
}
return applyOperations();
}
@@ -877,15 +880,6 @@ public class GridSizeMigrationTask {
return dup;
}
- private static Point parsePoint(String point) {
- String[] split = point.split(",");
- return new Point(Integer.parseInt(split[0]), Integer.parseInt(split[1]));
- }
-
- private static String getPointString(int x, int y) {
- return String.format(Locale.ENGLISH, "%d,%d", x, y);
- }
-
public static void markForMigration(
Context context, int gridX, int gridY, int hotseatSize) {
Utilities.getPrefs(context).edit()
diff --git a/src/com/android/launcher3/model/LoaderCursor.java b/src/com/android/launcher3/model/LoaderCursor.java
index 8efebf14b9..d104a8b22f 100644
--- a/src/com/android/launcher3/model/LoaderCursor.java
+++ b/src/com/android/launcher3/model/LoaderCursor.java
@@ -380,7 +380,7 @@ public class LoaderCursor extends CursorWrapper {
* otherwise marks it for deletion.
*/
public void checkAndAddItem(ItemInfo info, BgDataModel dataModel) {
- if (checkItemPlacement(info, dataModel.workspaceScreens)) {
+ if (checkItemPlacement(info)) {
dataModel.addItem(mContext, info, false);
} else {
markDeleted("Item position overlap");
@@ -390,7 +390,7 @@ public class LoaderCursor extends CursorWrapper {
/**
* check & update map of what's occupied; used to discard overlapping/invalid items
*/
- protected boolean checkItemPlacement(ItemInfo item, IntArray workspaceScreens) {
+ protected boolean checkItemPlacement(ItemInfo item) {
int containerIndex = item.screenId;
if (item.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {
final GridOccupancy hotseatOccupancy =
@@ -420,12 +420,7 @@ public class LoaderCursor extends CursorWrapper {
occupied.put(LauncherSettings.Favorites.CONTAINER_HOTSEAT, occupancy);
return true;
}
- } else if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {
- if (!workspaceScreens.contains(item.screenId)) {
- // The item has an invalid screen id.
- return false;
- }
- } else {
+ } else if (item.container != LauncherSettings.Favorites.CONTAINER_DESKTOP) {
// Skip further checking if it is not the hotseat or workspace container
return true;
}
diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java
index f711787cfe..a4fe57086a 100644
--- a/src/com/android/launcher3/model/LoaderTask.java
+++ b/src/com/android/launcher3/model/LoaderTask.java
@@ -72,6 +72,7 @@ import com.android.launcher3.shortcuts.ShortcutInfoCompat;
import com.android.launcher3.shortcuts.ShortcutKey;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.IntArray;
+import com.android.launcher3.util.IntSet;
import com.android.launcher3.util.LooperIdleLock;
import com.android.launcher3.util.MultiHashMap;
import com.android.launcher3.util.PackageManagerHelper;
@@ -293,7 +294,6 @@ public class LoaderTask implements Runnable {
final HashMap installingPkgs =
mPackageInstaller.updateAndGetActiveSessionCache();
mFirstScreenBroadcast = new FirstScreenBroadcast(installingPkgs);
- mBgDataModel.workspaceScreens.addAll(LauncherModel.loadWorkspaceScreensDb(context));
Map shortcutKeyToPinnedShortcuts = new HashMap<>();
final LoaderCursor c = new LoaderCursor(contentResolver.query(
@@ -780,21 +780,15 @@ public class LoaderTask implements Runnable {
new Handler(LauncherModel.getWorkerLooper()));
}
- // Remove any empty screens
- IntArray unusedScreens = mBgDataModel.workspaceScreens.clone();
+ // Initialize the screens array. Using an InstSet ensures that the screen ids
+ // are sorted.
+ IntSet screenSet = new IntSet();
for (ItemInfo item: mBgDataModel.itemsIdMap) {
- int screenId = item.screenId;
- if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&
- unusedScreens.contains(screenId)) {
- unusedScreens.removeValue(screenId);
+ if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {
+ screenSet.add(item.screenId);
}
}
-
- // If there are any empty screens remove them, and update.
- if (unusedScreens.size() != 0) {
- mBgDataModel.workspaceScreens.removeAllValues(unusedScreens);
- LauncherModel.updateWorkspaceScreenOrder(context, mBgDataModel.workspaceScreens);
- }
+ mBgDataModel.workspaceScreens.addAll(screenSet.getArray());
}
}
diff --git a/src/com/android/launcher3/model/ModelWriter.java b/src/com/android/launcher3/model/ModelWriter.java
index f7961d5d87..ca5428d94d 100644
--- a/src/com/android/launcher3/model/ModelWriter.java
+++ b/src/com/android/launcher3/model/ModelWriter.java
@@ -333,7 +333,7 @@ public class ModelWriter {
* {@link #commitDelete()} is called (or abandoned if {@link #abortDelete()} is called).
* Otherwise, we run the Runnable immediately.
*/
- public void enqueueDeleteRunnable(Runnable r) {
+ private void enqueueDeleteRunnable(Runnable r) {
if (mPreparingToUndo) {
mDeleteRunnables.add(r);
} else {
diff --git a/src/com/android/launcher3/provider/ImportDataTask.java b/src/com/android/launcher3/provider/ImportDataTask.java
index e1b26980c1..86fcc06802 100644
--- a/src/com/android/launcher3/provider/ImportDataTask.java
+++ b/src/com/android/launcher3/provider/ImportDataTask.java
@@ -33,7 +33,6 @@ import android.os.Process;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.SparseBooleanArray;
-import android.util.SparseIntArray;
import com.android.launcher3.AutoInstallsLayout.LayoutParserCallback;
import com.android.launcher3.DefaultLayoutParser;
@@ -43,8 +42,6 @@ import com.android.launcher3.LauncherProvider;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.LauncherSettings.Settings;
-import com.android.launcher3.LauncherSettings.WorkspaceScreens;
-import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.Workspace;
import com.android.launcher3.compat.UserManagerCompat;
@@ -73,7 +70,6 @@ public class ImportDataTask {
private final Context mContext;
- private final Uri mOtherScreensUri;
private final Uri mOtherFavoritesUri;
private int mHotseatSize;
@@ -82,41 +78,14 @@ public class ImportDataTask {
private ImportDataTask(Context context, String sourceAuthority) {
mContext = context;
- mOtherScreensUri = Uri.parse("content://" +
- sourceAuthority + "/" + WorkspaceScreens.TABLE_NAME);
mOtherFavoritesUri = Uri.parse("content://" + sourceAuthority + "/" + Favorites.TABLE_NAME);
}
public boolean importWorkspace() throws Exception {
- IntArray allScreens = LauncherDbUtils.getScreenIdsFromCursor(
- mContext.getContentResolver().query(mOtherScreensUri, null, null, null,
- LauncherSettings.WorkspaceScreens.SCREEN_RANK));
FileLog.d(TAG, "Importing DB from " + mOtherFavoritesUri);
- // During import we reset the screen IDs to 0-indexed values.
- if (allScreens.isEmpty()) {
- // No thing to migrate
- FileLog.e(TAG, "No data found to import");
- return false;
- }
-
mHotseatSize = mMaxGridSizeX = mMaxGridSizeY = 0;
-
- // Build screen update
- ArrayList screenOps = new ArrayList<>();
- int count = allScreens.size();
- SparseIntArray screenIdMap = new SparseIntArray(count);
- for (int i = 0; i < count; i++) {
- ContentValues v = new ContentValues();
- v.put(LauncherSettings.WorkspaceScreens._ID, i);
- v.put(LauncherSettings.WorkspaceScreens.SCREEN_RANK, i);
- screenIdMap.put(allScreens.get(i), i);
- screenOps.add(ContentProviderOperation.newInsert(
- LauncherSettings.WorkspaceScreens.CONTENT_URI).withValues(v).build());
- }
- mContext.getContentResolver().applyBatch(LauncherProvider.AUTHORITY, screenOps);
- importWorkspaceItems(allScreens.get(0), screenIdMap);
-
+ importWorkspaceItems();
GridSizeMigrationTask.markForMigration(mContext, mMaxGridSizeX, mMaxGridSizeY, mHotseatSize);
// Create empty DB flag.
@@ -130,17 +99,17 @@ public class ImportDataTask {
* 2) For home screen entries, maps the screen id based on {@param screenIdMap}
* 3) In the end fills any holes in hotseat with items from default hotseat layout.
*/
- private void importWorkspaceItems(
- int firstScreenId, SparseIntArray screenIdMap) throws Exception {
+ private void importWorkspaceItems() throws Exception {
String profileId = Long.toString(UserManagerCompat.getInstance(mContext)
.getSerialNumberForUser(Process.myUserHandle()));
boolean createEmptyRowOnFirstScreen;
if (FeatureFlags.QSB_ON_FIRST_SCREEN.get()) {
try (Cursor c = mContext.getContentResolver().query(mOtherFavoritesUri, null,
- // get items on the first row of the first screen
- "profileId = ? AND container = -100 AND screen = ? AND cellY = 0",
- new String[]{profileId, Integer.toString(firstScreenId)},
+ // get items on the first row of the first screen (min screen id)
+ "profileId = ? AND container = -100 AND cellY = 0 AND screen = " +
+ "(SELECT MIN(screen) FROM favorites WHERE container = -100)",
+ new String[]{profileId},
null)) {
// First row of first screen is not empty
createEmptyRowOnFirstScreen = c.moveToNext();
@@ -164,7 +133,7 @@ public class ImportDataTask {
Favorites.PROFILE_ID + " = ?", new String[]{profileId},
// Get the items sorted by container, so that the folders are loaded
// before the corresponding items.
- Favorites.CONTAINER)) {
+ Favorites.CONTAINER + " , " + Favorites.SCREEN)) {
// various columns we expect to exist.
final int idIndex = c.getColumnIndexOrThrow(Favorites._ID);
@@ -186,6 +155,7 @@ public class ImportDataTask {
SparseBooleanArray mValidFolders = new SparseBooleanArray();
ContentValues values = new ContentValues();
+ Integer firstScreenId = null;
while (c.moveToNext()) {
values.clear();
int id = c.getInt(idIndex);
@@ -202,16 +172,21 @@ public class ImportDataTask {
switch (container) {
case Favorites.CONTAINER_DESKTOP: {
- Integer newScreenId = screenIdMap.get(screen);
- if (newScreenId == null) {
- FileLog.d(TAG, String.format("Skipping item %d, type %d not on a valid screen %d", id, type, screen));
+ if (screen < Workspace.FIRST_SCREEN_ID) {
+ FileLog.d(TAG, String.format(
+ "Skipping item %d, type %d not on a valid screen %d",
+ id, type, screen));
continue;
}
+ if (firstScreenId == null) {
+ firstScreenId = screen;
+ }
// Reset the screen to 0-index value
- screen = newScreenId;
- if (createEmptyRowOnFirstScreen && screen == Workspace.FIRST_SCREEN_ID) {
+ if (createEmptyRowOnFirstScreen && firstScreenId.equals(screen)) {
// Shift items by 1.
cellY++;
+ // Change the screen id to first screen
+ screen = Workspace.FIRST_SCREEN_ID;
}
mMaxGridSizeX = Math.max(mMaxGridSizeX, cellX + spanX);
@@ -219,7 +194,7 @@ public class ImportDataTask {
break;
}
case Favorites.CONTAINER_HOTSEAT: {
- mHotseatSize = Math.max(mHotseatSize, (int) screen + 1);
+ mHotseatSize = Math.max(mHotseatSize, screen + 1);
break;
}
default:
@@ -378,18 +353,13 @@ public class ImportDataTask {
return false;
}
- private static int getMyHotseatLayoutId(Context context) {
- return LauncherAppState.getIDP(context).numHotseatIcons <= 5
- ? R.xml.dw_phone_hotseat
- : R.xml.dw_tablet_hotseat;
- }
-
/**
* Extension of {@link DefaultLayoutParser} which only allows icons and shortcuts.
*/
private static class HotseatLayoutParser extends DefaultLayoutParser {
public HotseatLayoutParser(Context context, LayoutParserCallback callback) {
- super(context, null, callback, context.getResources(), getMyHotseatLayoutId(context));
+ super(context, null, callback, context.getResources(),
+ LauncherAppState.getIDP(context).defaultLayoutId);
}
@Override
@@ -434,6 +404,12 @@ public class ImportDataTask {
// No need to add more items.
return 0;
}
+ if (!Integer.valueOf(Favorites.CONTAINER_HOTSEAT)
+ .equals(values.getAsInteger(Favorites.CONTAINER))) {
+ // Ignore items which are not for hotseat.
+ return 0;
+ }
+
Intent intent;
try {
intent = Intent.parseUri(values.getAsString(Favorites.INTENT), 0);
diff --git a/src/com/android/launcher3/provider/LauncherDbUtils.java b/src/com/android/launcher3/provider/LauncherDbUtils.java
index ab0703fed2..b79478ac6f 100644
--- a/src/com/android/launcher3/provider/LauncherDbUtils.java
+++ b/src/com/android/launcher3/provider/LauncherDbUtils.java
@@ -25,11 +25,9 @@ import android.util.Log;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherSettings.Favorites;
-import com.android.launcher3.LauncherSettings.WorkspaceScreens;
import com.android.launcher3.util.IntArray;
-import java.util.ArrayList;
-import java.util.Collection;
+import java.util.Locale;
/**
* A set of utility methods for Launcher DB used for DB updates and migration.
@@ -47,26 +45,25 @@ public class LauncherDbUtils {
*/
public static boolean prepareScreenZeroToHostQsb(Context context, SQLiteDatabase db) {
try (SQLiteTransaction t = new SQLiteTransaction(db)) {
- // Get the existing screens
- IntArray screenIds = getScreenIdsFromCursor(db.query(WorkspaceScreens.TABLE_NAME,
- null, null, null, null, null, WorkspaceScreens.SCREEN_RANK));
+ // Get the first screen
+ final int firstScreenId;
+ try (Cursor c = db.rawQuery(String.format(Locale.ENGLISH,
+ "SELECT MIN(%1$s) from %2$s where %3$s = %4$d",
+ Favorites.SCREEN, Favorites.TABLE_NAME, Favorites.CONTAINER,
+ Favorites.CONTAINER_DESKTOP), null)) {
- if (screenIds.isEmpty()) {
- // No update needed
- t.commit();
- return true;
- }
- if (screenIds.get(0) != 0) {
- // First screen is not 0, we need to rename screens
- if (screenIds.contains(0)) {
- // There is already a screen 0. First rename it to a different screen.
- int newScreenId = 1;
- while (screenIds.contains(newScreenId)) newScreenId++;
- renameScreen(db, 0, newScreenId);
+ if (!c.moveToNext()) {
+ // No update needed
+ t.commit();
+ return true;
}
+ firstScreenId = c.getInt(0);
+ }
+
+ if (firstScreenId != 0) {
// Rename the first screen to 0.
- renameScreen(db, screenIds.get(0), 0);
+ renameScreen(db, firstScreenId, 0);
}
// Check if the first row is empty
@@ -89,31 +86,19 @@ public class LauncherDbUtils {
private static void renameScreen(SQLiteDatabase db, int oldScreen, int newScreen) {
String[] whereParams = new String[] { Integer.toString(oldScreen) };
-
ContentValues values = new ContentValues();
- values.put(WorkspaceScreens._ID, newScreen);
- db.update(WorkspaceScreens.TABLE_NAME, values, "_id = ?", whereParams);
-
- values.clear();
values.put(Favorites.SCREEN, newScreen);
db.update(Favorites.TABLE_NAME, values, "container = -100 and screen = ?", whereParams);
}
- /**
- * Parses the cursor containing workspace screens table and returns the list of screen IDs
- */
- public static IntArray getScreenIdsFromCursor(Cursor sc) {
- try {
- return iterateCursor(sc,
- sc.getColumnIndexOrThrow(WorkspaceScreens._ID), new IntArray());
- } finally {
- sc.close();
- }
- }
-
- public static IntArray iterateCursor(Cursor c, int columnIndex, IntArray out) {
- while (c.moveToNext()) {
- out.add(c.getInt(columnIndex));
+ public static IntArray queryIntArray(SQLiteDatabase db, String tableName, String columnName,
+ String selection, String groupBy, String orderBy) {
+ IntArray out = new IntArray();
+ try (Cursor c = db.query(tableName, new String[] { columnName }, selection, null,
+ groupBy, null, orderBy)) {
+ while (c.moveToNext()) {
+ out.add(c.getInt(0));
+ }
}
return out;
}
diff --git a/src/com/android/launcher3/settings/SettingsActivity.java b/src/com/android/launcher3/settings/SettingsActivity.java
index 77682e55e3..6e7188f3c9 100644
--- a/src/com/android/launcher3/settings/SettingsActivity.java
+++ b/src/com/android/launcher3/settings/SettingsActivity.java
@@ -32,11 +32,9 @@ import com.android.launcher3.LauncherFiles;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.config.FeatureFlags;
-import com.android.launcher3.graphics.IconShapeOverride;
import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
import com.android.launcher3.util.SecureSettingsObserver;
-import androidx.preference.ListPreference;
import androidx.preference.Preference;
import androidx.preference.PreferenceFragment;
import androidx.preference.PreferenceFragment.OnPreferenceStartFragmentCallback;
@@ -185,13 +183,6 @@ public class SettingsActivity extends Activity
case ADD_ICON_PREFERENCE_KEY:
return Utilities.ATLEAST_OREO;
- case IconShapeOverride.KEY_PREFERENCE:
- if (!IconShapeOverride.isSupported(getActivity())) {
- return false;
- }
- IconShapeOverride.handlePreferenceUi((ListPreference) preference);
- return true;
-
case ALLOW_ROTATION_PREFERENCE_KEY:
if (getResources().getBoolean(R.bool.allow_rotation)) {
// Launcher supports rotation by default. No need to show this setting.
diff --git a/src/com/android/launcher3/util/IntSet.java b/src/com/android/launcher3/util/IntSet.java
index 63499b06d6..2459fad327 100644
--- a/src/com/android/launcher3/util/IntSet.java
+++ b/src/com/android/launcher3/util/IntSet.java
@@ -48,4 +48,15 @@ public class IntSet {
public int size() {
return mArray.size();
}
+
+ public IntArray getArray() {
+ return mArray;
+ }
+
+ public static IntSet wrap(IntArray array) {
+ IntSet set = new IntSet();
+ set.mArray.addAll(array);
+ Arrays.sort(set.mArray.mValues, 0, set.mArray.mSize);
+ return set;
+ }
}
diff --git a/src/com/android/launcher3/util/RaceConditionTracker.java b/src/com/android/launcher3/util/RaceConditionTracker.java
index 8eafb551dc..8b0678784a 100644
--- a/src/com/android/launcher3/util/RaceConditionTracker.java
+++ b/src/com/android/launcher3/util/RaceConditionTracker.java
@@ -22,6 +22,9 @@ package com.android.launcher3.util;
* orders.
*/
public class RaceConditionTracker {
+ public final static boolean ENTER = true;
+ public final static boolean EXIT = false;
+
public interface EventProcessor {
void onEvent(String eventName);
}
@@ -35,4 +38,22 @@ public class RaceConditionTracker {
public static void onEvent(String eventName) {
if (sEventProcessor != null) sEventProcessor.onEvent(eventName);
}
+
+ public static void onEvent(String eventName, boolean isEnter) {
+ if (sEventProcessor != null) {
+ sEventProcessor.onEvent(enterExitEvt(eventName, isEnter));
+ }
+ }
+
+ public static String enterExitEvt(String eventName, boolean isEnter) {
+ return eventName + ":" + (isEnter ? "enter" : "exit");
+ }
+
+ public static String enterEvt(String eventName) {
+ return enterExitEvt(eventName, ENTER);
+ }
+
+ public static String exitEvt(String eventName) {
+ return enterExitEvt(eventName, EXIT);
+ }
}
diff --git a/src/com/android/launcher3/util/TraceHelper.java b/src/com/android/launcher3/util/TraceHelper.java
index 4aa2f37885..a321bcc205 100644
--- a/src/com/android/launcher3/util/TraceHelper.java
+++ b/src/com/android/launcher3/util/TraceHelper.java
@@ -39,7 +39,7 @@ public class TraceHelper {
private static final boolean SYSTEM_TRACE = false;
private static final ArrayMap sUpTimes = ENABLED ? new ArrayMap<>() : null;
- public static void beginSection(String sectionName) {
+ public static synchronized void beginSection(String sectionName) {
if (ENABLED) {
MutableLong time = sUpTimes.get(sectionName);
if (time == null) {
@@ -55,7 +55,7 @@ public class TraceHelper {
}
}
- public static void partitionSection(String sectionName, String partition) {
+ public static synchronized void partitionSection(String sectionName, String partition) {
if (ENABLED) {
MutableLong time = sUpTimes.get(sectionName);
if (time != null && time.value >= 0) {
@@ -78,7 +78,7 @@ public class TraceHelper {
}
}
- public static void endSection(String sectionName, String msg) {
+ public static synchronized void endSection(String sectionName, String msg) {
if (ENABLED) {
MutableLong time = sUpTimes.get(sectionName);
if (time != null && time.value >= 0) {
diff --git a/tests/src/com/android/launcher3/model/LoaderCursorTest.java b/tests/src/com/android/launcher3/model/LoaderCursorTest.java
index ac1be1777a..df935b8dbe 100644
--- a/tests/src/com/android/launcher3/model/LoaderCursorTest.java
+++ b/tests/src/com/android/launcher3/model/LoaderCursorTest.java
@@ -18,16 +18,12 @@ import com.android.launcher3.ShortcutInfo;
import com.android.launcher3.Utilities;
import com.android.launcher3.compat.LauncherAppsCompat;
import com.android.launcher3.icons.BitmapInfo;
-import com.android.launcher3.util.IntArray;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import java.util.ArrayList;
-import java.util.Arrays;
-
-import static com.android.launcher3.LauncherSettings.BaseLauncherColumns.INTENT;
+import static com.android.launcher3.LauncherSettings.Favorites.INTENT;
import static com.android.launcher3.LauncherSettings.Favorites.CELLX;
import static com.android.launcher3.LauncherSettings.Favorites.CELLY;
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER;
@@ -148,81 +144,57 @@ public class LoaderCursorTest {
assertEquals(ITEM_TYPE_SHORTCUT, info.itemType);
}
- @Test
- public void checkItemPlacement_wrongWorkspaceScreen() {
- IntArray workspaceScreens = IntArray.wrap(1, 3);
- mIDP.numRows = 4;
- mIDP.numColumns = 4;
- mIDP.numHotseatIcons = 3;
-
- // Item on unknown screen are not placed
- assertFalse(mLoaderCursor.checkItemPlacement(
- newItemInfo(0, 0, 1, 1, CONTAINER_DESKTOP, 4), workspaceScreens));
- assertFalse(mLoaderCursor.checkItemPlacement(
- newItemInfo(0, 0, 1, 1, CONTAINER_DESKTOP, 5), workspaceScreens));
- assertFalse(mLoaderCursor.checkItemPlacement(
- newItemInfo(0, 0, 1, 1, CONTAINER_DESKTOP, 2), workspaceScreens));
-
- assertTrue(mLoaderCursor.checkItemPlacement(
- newItemInfo(0, 0, 1, 1, CONTAINER_DESKTOP, 1), workspaceScreens));
- assertTrue(mLoaderCursor.checkItemPlacement(
- newItemInfo(0, 0, 1, 1, CONTAINER_DESKTOP, 3), workspaceScreens));
-
- }
@Test
public void checkItemPlacement_outsideBounds() {
- IntArray workspaceScreens = IntArray.wrap(1, 2);
mIDP.numRows = 4;
mIDP.numColumns = 4;
mIDP.numHotseatIcons = 3;
// Item outside screen bounds are not placed
assertFalse(mLoaderCursor.checkItemPlacement(
- newItemInfo(4, 4, 1, 1, CONTAINER_DESKTOP, 1), workspaceScreens));
+ newItemInfo(4, 4, 1, 1, CONTAINER_DESKTOP, 1)));
}
@Test
public void checkItemPlacement_overlappingItems() {
- IntArray workspaceScreens = IntArray.wrap(1, 2);
mIDP.numRows = 4;
mIDP.numColumns = 4;
mIDP.numHotseatIcons = 3;
// Overlapping items are not placed
assertTrue(mLoaderCursor.checkItemPlacement(
- newItemInfo(0, 0, 1, 1, CONTAINER_DESKTOP, 1), workspaceScreens));
+ newItemInfo(0, 0, 1, 1, CONTAINER_DESKTOP, 1)));
assertFalse(mLoaderCursor.checkItemPlacement(
- newItemInfo(0, 0, 1, 1, CONTAINER_DESKTOP, 1), workspaceScreens));
+ newItemInfo(0, 0, 1, 1, CONTAINER_DESKTOP, 1)));
assertTrue(mLoaderCursor.checkItemPlacement(
- newItemInfo(0, 0, 1, 1, CONTAINER_DESKTOP, 2), workspaceScreens));
+ newItemInfo(0, 0, 1, 1, CONTAINER_DESKTOP, 2)));
assertFalse(mLoaderCursor.checkItemPlacement(
- newItemInfo(0, 0, 1, 1, CONTAINER_DESKTOP, 2), workspaceScreens));
+ newItemInfo(0, 0, 1, 1, CONTAINER_DESKTOP, 2)));
assertTrue(mLoaderCursor.checkItemPlacement(
- newItemInfo(1, 1, 1, 1, CONTAINER_DESKTOP, 1), workspaceScreens));
+ newItemInfo(1, 1, 1, 1, CONTAINER_DESKTOP, 1)));
assertTrue(mLoaderCursor.checkItemPlacement(
- newItemInfo(2, 2, 2, 2, CONTAINER_DESKTOP, 1), workspaceScreens));
+ newItemInfo(2, 2, 2, 2, CONTAINER_DESKTOP, 1)));
assertFalse(mLoaderCursor.checkItemPlacement(
- newItemInfo(3, 2, 1, 2, CONTAINER_DESKTOP, 1), workspaceScreens));
+ newItemInfo(3, 2, 1, 2, CONTAINER_DESKTOP, 1)));
}
@Test
public void checkItemPlacement_hotseat() {
- IntArray workspaceScreens = new IntArray();
mIDP.numRows = 4;
mIDP.numColumns = 4;
mIDP.numHotseatIcons = 3;
// Hotseat items are only placed based on screenId
assertTrue(mLoaderCursor.checkItemPlacement(
- newItemInfo(3, 3, 1, 1, CONTAINER_HOTSEAT, 1), workspaceScreens));
+ newItemInfo(3, 3, 1, 1, CONTAINER_HOTSEAT, 1)));
assertTrue(mLoaderCursor.checkItemPlacement(
- newItemInfo(3, 3, 1, 1, CONTAINER_HOTSEAT, 2), workspaceScreens));
+ newItemInfo(3, 3, 1, 1, CONTAINER_HOTSEAT, 2)));
assertFalse(mLoaderCursor.checkItemPlacement(
- newItemInfo(3, 3, 1, 1, CONTAINER_HOTSEAT, 3), workspaceScreens));
+ newItemInfo(3, 3, 1, 1, CONTAINER_HOTSEAT, 3)));
}
private ItemInfo newItemInfo(int cellX, int cellY, int spanX, int spanY,
diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index bc5aaeeb75..8c03e4b5f6 100644
--- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -17,6 +17,7 @@ package com.android.launcher3.ui;
import static androidx.test.InstrumentationRegistry.getInstrumentation;
+import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import android.app.Instrumentation;
@@ -25,11 +26,13 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.LauncherActivityInfo;
+import android.content.pm.PackageManager;
import android.os.Process;
import android.os.RemoteException;
import android.view.Surface;
import androidx.test.InstrumentationRegistry;
+import androidx.test.uiautomator.By;
import androidx.test.uiautomator.BySelector;
import androidx.test.uiautomator.Direction;
import androidx.test.uiautomator.UiDevice;
@@ -77,6 +80,7 @@ public abstract class AbstractLauncherUiTest {
public static final long SHORT_UI_TIMEOUT= 300;
public static final long DEFAULT_UI_TIMEOUT = 10000;
+ protected static final int LONG_WAIT_TIME_MS = 60000;
protected MainThreadExecutor mMainThreadExecutor = new MainThreadExecutor();
protected final UiDevice mDevice;
@@ -325,4 +329,33 @@ public abstract class AbstractLauncherUiTest {
return intent == null ? null : (Intent) intent.getParcelableExtra(Intent.EXTRA_INTENT);
}
}
+
+ protected void startAppFast(String packageName) {
+ final Instrumentation instrumentation = getInstrumentation();
+ final Intent intent = instrumentation.getContext().getPackageManager().
+ getLaunchIntentForPackage(packageName);
+ intent.addCategory(Intent.CATEGORY_LAUNCHER);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ instrumentation.getTargetContext().startActivity(intent);
+ assertTrue(packageName + " didn't start",
+ mDevice.wait(Until.hasObject(By.pkg(packageName).depth(0)), LONG_WAIT_TIME_MS));
+ }
+
+ protected String resolveSystemApp(String category) {
+ return getInstrumentation().getContext().getPackageManager().resolveActivity(
+ new Intent(Intent.ACTION_MAIN).addCategory(category),
+ PackageManager.MATCH_SYSTEM_ONLY).
+ activityInfo.packageName;
+ }
+
+ protected void closeLauncherActivity() {
+ // Destroy Launcher activity.
+ executeOnLauncher(launcher -> {
+ if (launcher != null) {
+ launcher.finish();
+ }
+ });
+ waitForLauncherCondition(
+ "Launcher still active", launcher -> launcher == null, DEFAULT_UI_TIMEOUT);
+ }
}
diff --git a/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java
index 22bc05c942..8b8e43626c 100644
--- a/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java
@@ -297,10 +297,6 @@ public class BindWidgetTest extends AbstractLauncherUiTest {
if (screenId > Workspace.FIRST_SCREEN_ID) {
screenId = Workspace.FIRST_SCREEN_ID;
}
- ContentValues v = new ContentValues();
- v.put(LauncherSettings.WorkspaceScreens._ID, screenId);
- v.put(LauncherSettings.WorkspaceScreens.SCREEN_RANK, 0);
- mResolver.insert(LauncherSettings.WorkspaceScreens.CONTENT_URI, v);
// Insert the item
ContentWriter writer = new ContentWriter(mTargetContext);
diff --git a/tests/src/com/android/launcher3/util/RaceConditionReproducer.java b/tests/src/com/android/launcher3/util/RaceConditionReproducer.java
index c4350de0b7..316e40d825 100644
--- a/tests/src/com/android/launcher3/util/RaceConditionReproducer.java
+++ b/tests/src/com/android/launcher3/util/RaceConditionReproducer.java
@@ -43,6 +43,11 @@ import java.util.concurrent.TimeUnit;
* executing events in previously unseen order. It does it by postponing execution of threads that
* would lead to an already seen sequence.
*
+ * If an event A occurs before event B in the sequence, this is how execution order looks like:
+ * Events: ... A ... B ...
+ * Events and instructions, guaranteed order:
+ * (instructions executed prior to A) A ... B (instructions executed after B)
+ *
* Each iteration has 3 parts (phases).
* Phase 1. Picking a previously seen event subsequence that we believe can have previously unseen
* continuations. Reproducing this sequence by pausing threads that would lead to other sequences.
@@ -178,6 +183,10 @@ public class RaceConditionReproducer implements RaceConditionTracker.EventProces
mReproString = reproString;
}
+ public RaceConditionReproducer(String... reproSequence) {
+ this(String.join("|", reproSequence));
+ }
+
public synchronized String getCurrentSequenceString() {
return mCurrentSequence.toString();
}
diff --git a/tests/tapl/com/android/launcher3/tapl/Workspace.java b/tests/tapl/com/android/launcher3/tapl/Workspace.java
index c63822e2ea..c45f0f0d81 100644
--- a/tests/tapl/com/android/launcher3/tapl/Workspace.java
+++ b/tests/tapl/com/android/launcher3/tapl/Workspace.java
@@ -46,28 +46,16 @@ public final class Workspace extends Home {
@NonNull
public AllApps switchToAllApps() {
verifyActiveContainer();
- if (mLauncher.isSwipeUpEnabled()) {
- int midX = mLauncher.getDevice().getDisplayWidth() / 2;
- int height = mLauncher.getDevice().getDisplayHeight();
- // Swipe from 6/7ths down the screen to 1/7th down the screen.
- mLauncher.swipe(
- midX,
- height * 6 / 7,
- midX,
- height / 7
- );
- } else {
- // Swipe from the hotseat to near the top, e.g. 10% of the screen.
- final UiObject2 hotseat = mHotseat;
- final Point start = hotseat.getVisibleCenter();
- final int endY = (int) (mLauncher.getDevice().getDisplayHeight() * 0.1f);
- mLauncher.swipe(
- start.x,
- start.y,
- start.x,
- endY
- );
- }
+ // Swipe from the hotseat to near the top, e.g. 10% of the screen.
+ final UiObject2 hotseat = mHotseat;
+ final Point start = hotseat.getVisibleCenter();
+ final int endY = (int) (mLauncher.getDevice().getDisplayHeight() * 0.1f);
+ mLauncher.swipe(
+ start.x,
+ start.y,
+ start.x,
+ endY
+ );
return new AllApps(mLauncher);
}