diff options
398 files changed, 13539 insertions, 6930 deletions
diff --git a/Android.mk b/Android.mk index dbce33f8b..110117be4 100644 --- a/Android.mk +++ b/Android.mk @@ -36,7 +36,7 @@ LOCAL_AAPT_FLAGS := --auto-add-overlay LOCAL_PROTOC_OPTIMIZE_TYPE := nano LOCAL_PROTOC_FLAGS := --proto_path=$(LOCAL_PATH)/protos/ -LOCAL_SDK_VERSION := 19 +LOCAL_SDK_VERSION := 21 LOCAL_PACKAGE_NAME := Launcher3 #LOCAL_CERTIFICATE := shared diff --git a/AndroidManifest.xml b/AndroidManifest.xml index d4cd6a2be..591d9b612 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -20,13 +20,9 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.launcher3"> - <uses-sdk android:targetSdkVersion="19" android:minSdkVersion="16"/> + <uses-sdk android:targetSdkVersion="21" android:minSdkVersion="16"/> <permission - android:name="com.android.launcher3.permission.PRELOAD_WORKSPACE" - android:permissionGroup="android.permission-group.SYSTEM_TOOLS" - android:protectionLevel="signatureOrSystem" /> - <permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" android:permissionGroup="android.permission-group.SYSTEM_TOOLS" android:protectionLevel="dangerous" @@ -50,11 +46,13 @@ android:protectionLevel="signatureOrSystem" android:label="@string/permlab_write_settings" android:description="@string/permdesc_write_settings"/> - <permission android:name="com.android.launcher3.permission.RECEIVE_LAUNCH_BROADCASTS" android:protectionLevel="signature" /> + <permission + android:name="com.android.launcher3.permission.RECEIVE_FIRST_LOAD_BROADCAST" + android:protectionLevel="signatureOrSystem" /> <uses-permission android:name="android.permission.CALL_PHONE" /> <uses-permission android:name="android.permission.SET_WALLPAPER" /> @@ -63,19 +61,26 @@ <uses-permission android:name="android.permission.BIND_APPWIDGET" /> <uses-permission android:name="android.permission.GET_ACCOUNTS" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> + <uses-permission android:name="android.permission.BROADCAST_STICKY"/> + <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> <uses-permission android:name="com.android.launcher.permission.READ_SETTINGS" /> <uses-permission android:name="com.android.launcher.permission.WRITE_SETTINGS" /> <uses-permission android:name="com.android.launcher3.permission.READ_SETTINGS" /> <uses-permission android:name="com.android.launcher3.permission.WRITE_SETTINGS" /> <uses-permission android:name="com.android.launcher3.permission.RECEIVE_LAUNCH_BROADCASTS" /> + <uses-permission android:name="com.android.launcher3.permission.RECEIVE_FIRST_LOAD_BROADCAST" /> <application android:name="com.android.launcher3.LauncherApplication" - android:label="@string/application_name" - android:icon="@mipmap/ic_launcher_home" + android:allowBackup="@bool/enable_backup" + android:backupAgent="com.android.launcher3.LauncherBackupAgentHelper" android:hardwareAccelerated="true" + android:icon="@mipmap/ic_launcher_home" + android:label="@string/application_name" android:largeHeap="@bool/config_largeHeap" - android:supportsRtl="true"> + android:restoreAnyVersion="true" + android:supportsRtl="true" > + <activity android:name="com.android.launcher3.Launcher" android:launchMode="singleTask" @@ -152,15 +157,6 @@ > </service> - <!-- Intent received used to prepopulate the default workspace. --> - <receiver - android:name="com.android.launcher3.PreloadReceiver" - android:permission="com.android.launcher3.permission.PRELOAD_WORKSPACE"> - <intent-filter> - <action android:name="com.android.launcher3.action.PRELOAD_WORKSPACE" /> - </intent-filter> - </receiver> - <receiver android:name="com.android.launcher3.WallpaperChangedReceiver"> <intent-filter> @@ -171,18 +167,25 @@ <!-- Intent received used to install shortcuts from other applications --> <receiver android:name="com.android.launcher3.InstallShortcutReceiver" - android:permission="com.android.launcher3.permission.INSTALL_SHORTCUT"> + android:permission="com.android.launcher.permission.INSTALL_SHORTCUT"> <intent-filter> - <action android:name="com.android.launcher3.action.INSTALL_SHORTCUT" /> + <action android:name="com.android.launcher.action.INSTALL_SHORTCUT" /> </intent-filter> </receiver> <!-- Intent received used to uninstall shortcuts from other applications --> <receiver android:name="com.android.launcher3.UninstallShortcutReceiver" - android:permission="com.android.launcher3.permission.UNINSTALL_SHORTCUT"> + android:permission="com.android.launcher.permission.UNINSTALL_SHORTCUT"> + <intent-filter> + <action android:name="com.android.launcher.action.UNINSTALL_SHORTCUT" /> + </intent-filter> + </receiver> + + <!-- Intent received used to initialize a restored widget --> + <receiver android:name="com.android.launcher3.AppWidgetsRestoredReceiver" > <intent-filter> - <action android:name="com.android.launcher3.action.UNINSTALL_SHORTCUT" /> + <action android:name="android.appwidget.action.APPWIDGET_HOST_RESTORED"/> </intent-filter> </receiver> @@ -204,6 +207,12 @@ </intent-filter> </receiver> + <receiver android:name="com.android.launcher3.StartupReceiver" > + <intent-filter> + <action android:name="android.intent.action.BOOT_COMPLETED" /> + </intent-filter> + </receiver> + <!-- The settings provider contains Home's data, like the workspace favorites --> <provider android:name="com.android.launcher3.LauncherProvider" diff --git a/WallpaperPicker/res/drawable-xxhdpi/ic_actionbar_accept.png b/WallpaperPicker/res/drawable-xxhdpi/ic_actionbar_accept.png Binary files differnew file mode 100755 index 000000000..d9ad51c9b --- /dev/null +++ b/WallpaperPicker/res/drawable-xxhdpi/ic_actionbar_accept.png diff --git a/WallpaperPicker/res/values-am/strings.xml b/WallpaperPicker/res/values-am/strings.xml index 394161634..59c3bf733 100644 --- a/WallpaperPicker/res/values-am/strings.xml +++ b/WallpaperPicker/res/values-am/strings.xml @@ -19,7 +19,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="wallpaper_instructions" msgid="3524143401182707094">"የግድግዳ ወረቀት አዘጋጅ"</string> + <string name="wallpaper_instructions" msgid="3524143401182707094">"ልጣፍ አዘጋጅ"</string> <string name="image_load_fail" msgid="7538534580694411837">"ምስሉን መጫን አልተቻለም"</string> <string name="wallpaper_load_fail" msgid="4800700444605404650">"ምስሉን እንደ ግድግዳ ወረቀት መጫን አልተቻለም"</string> <plurals name="number_of_items_selected"> @@ -27,10 +27,10 @@ <item quantity="one" msgid="8409622005831789373">"%1$d ተመርጧል"</item> <item quantity="other" msgid="479468347731745357">"%1$d ተመርጧል"</item> </plurals> - <string name="wallpaper_accessibility_name" msgid="4093221025304876354">"የግድግዳ ወረቀት %1$d የ%2$d"</string> + <string name="wallpaper_accessibility_name" msgid="4093221025304876354">"ልጣፍ %1$d የ%2$d"</string> <string name="announce_selection" msgid="123723511662250539">"<xliff:g id="LABEL">%1$s</xliff:g> ተመርጧል"</string> <string name="wallpaper_delete" msgid="1459353972739215344">"ሰርዝ"</string> <string name="pick_image" msgid="6704438906027442697">"ምስል ይምረጡ"</string> <string name="pick_wallpaper" msgid="4628969645948454559">"የግድግዳ ወረቀቶች"</string> - <string name="crop_wallpaper" msgid="4882870800623585836">"የግድግዳ ወረቀት ይከርክሙ"</string> + <string name="crop_wallpaper" msgid="4882870800623585836">"ልጣፍ ይከርክሙ"</string> </resources> diff --git a/WallpaperPicker/res/values-th/strings.xml b/WallpaperPicker/res/values-th/strings.xml index c81720563..6b4c23536 100644 --- a/WallpaperPicker/res/values-th/strings.xml +++ b/WallpaperPicker/res/values-th/strings.xml @@ -29,7 +29,7 @@ </plurals> <string name="wallpaper_accessibility_name" msgid="4093221025304876354">"วอลเปเปอร์ %1$d จาก %2$d"</string> <string name="announce_selection" msgid="123723511662250539">"เลือก <xliff:g id="LABEL">%1$s</xliff:g> แล้ว"</string> - <string name="wallpaper_delete" msgid="1459353972739215344">"นำออก"</string> + <string name="wallpaper_delete" msgid="1459353972739215344">"ลบ"</string> <string name="pick_image" msgid="6704438906027442697">"เลือกรูปภาพ"</string> <string name="pick_wallpaper" msgid="4628969645948454559">"วอลเปเปอร์"</string> <string name="crop_wallpaper" msgid="4882870800623585836">"ครอบตัดวอลเปเปอร์"</string> diff --git a/WallpaperPicker/src/com/android/launcher3/SavedWallpaperImages.java b/WallpaperPicker/src/com/android/launcher3/SavedWallpaperImages.java index 44bfdf1f9..2bdf8f1cd 100644 --- a/WallpaperPicker/src/com/android/launcher3/SavedWallpaperImages.java +++ b/WallpaperPicker/src/com/android/launcher3/SavedWallpaperImages.java @@ -34,8 +34,6 @@ import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.ListAdapter; -import com.android.photos.BitmapRegionTileSource; - import java.io.File; import java.io.FileOutputStream; import java.io.IOException; @@ -49,39 +47,17 @@ public class SavedWallpaperImages extends BaseAdapter implements ListAdapter { Context mContext; LayoutInflater mLayoutInflater; - public static class SavedWallpaperTile extends WallpaperPickerActivity.WallpaperTileInfo { + public static class SavedWallpaperTile extends WallpaperPickerActivity.FileWallpaperInfo { private int mDbId; - private Drawable mThumb; - public SavedWallpaperTile(int dbId, Drawable thumb) { + public SavedWallpaperTile(int dbId, File target, Drawable thumb) { + super(target, thumb); mDbId = dbId; - mThumb = thumb; - } - @Override - public void onClick(WallpaperPickerActivity a) { - String imageFilename = a.getSavedImages().getImageFilename(mDbId); - File file = new File(a.getFilesDir(), imageFilename); - BitmapRegionTileSource.FilePathBitmapSource bitmapSource = - new BitmapRegionTileSource.FilePathBitmapSource(file.getAbsolutePath(), 1024); - a.setCropViewTileSource(bitmapSource, false, true, null); - } - @Override - public void onSave(WallpaperPickerActivity a) { - boolean finishActivityWhenDone = true; - String imageFilename = a.getSavedImages().getImageFilename(mDbId); - a.setWallpaper(imageFilename, finishActivityWhenDone); } + @Override public void onDelete(WallpaperPickerActivity a) { a.getSavedImages().deleteImage(mDbId); } - @Override - public boolean isSelectable() { - return true; - } - @Override - public boolean isNamelessWallpaper() { - return true; - } } public SavedWallpaperImages(Activity context) { @@ -98,7 +74,8 @@ public class SavedWallpaperImages extends BaseAdapter implements ListAdapter { SQLiteDatabase db = mDb.getReadableDatabase(); Cursor result = db.query(ImageDb.TABLE_NAME, new String[] { ImageDb.COLUMN_ID, - ImageDb.COLUMN_IMAGE_THUMBNAIL_FILENAME }, // cols to return + ImageDb.COLUMN_IMAGE_THUMBNAIL_FILENAME, + ImageDb.COLUMN_IMAGE_FILENAME}, // cols to return null, // select query null, // args to select query null, @@ -112,7 +89,9 @@ public class SavedWallpaperImages extends BaseAdapter implements ListAdapter { Bitmap thumb = BitmapFactory.decodeFile(file.getAbsolutePath()); if (thumb != null) { - mImages.add(new SavedWallpaperTile(result.getInt(0), new BitmapDrawable(thumb))); + mImages.add(new SavedWallpaperTile(result.getInt(0), + new File(mContext.getFilesDir(), result.getString(2)), + new BitmapDrawable(thumb))); } } result.close(); @@ -136,15 +115,7 @@ public class SavedWallpaperImages extends BaseAdapter implements ListAdapter { Log.e(TAG, "Error decoding thumbnail for wallpaper #" + position); } return WallpaperPickerActivity.createImageTileView( - mLayoutInflater, position, convertView, parent, thumbDrawable); - } - - public String getImageFilename(int id) { - Pair<String, String> filenames = getImageFilenames(id); - if (filenames != null) { - return filenames.second; - } - return null; + mLayoutInflater, convertView, parent, thumbDrawable); } private Pair<String, String> getImageFilenames(int id) { diff --git a/WallpaperPicker/src/com/android/launcher3/WallpaperCropActivity.java b/WallpaperPicker/src/com/android/launcher3/WallpaperCropActivity.java index 561c4bb6a..d5c7cd93d 100644 --- a/WallpaperPicker/src/com/android/launcher3/WallpaperCropActivity.java +++ b/WallpaperPicker/src/com/android/launcher3/WallpaperCropActivity.java @@ -133,6 +133,14 @@ public class WallpaperCropActivity extends Activity { setCropViewTileSource(bitmapSource, true, false, onLoad); } + @Override + protected void onDestroy() { + if (mCropView != null) { + mCropView.destroy(); + } + super.onDestroy(); + } + public void setCropViewTileSource( final BitmapRegionTileSource.BitmapSource bitmapSource, final boolean touchEnabled, final boolean moveToLeft, final Runnable postExecute) { @@ -141,7 +149,21 @@ public class WallpaperCropActivity extends Activity { final AsyncTask<Void, Void, Void> loadBitmapTask = new AsyncTask<Void, Void, Void>() { protected Void doInBackground(Void...args) { if (!isCancelled()) { - bitmapSource.loadInBackground(); + try { + bitmapSource.loadInBackground(); + } catch (SecurityException securityException) { + if (isDestroyed()) { + // Temporarily granted permissions are revoked when the activity + // finishes, potentially resulting in a SecurityException here. + // Even though {@link #isDestroyed} might also return true in different + // situations where the configuration changes, we are fine with + // catching these cases here as well. + cancel(false); + } else { + // otherwise it had a different cause and we throw it further + throw securityException; + } + } } return null; } @@ -286,10 +308,10 @@ public class WallpaperCropActivity extends Activity { return 0; } - protected void setWallpaper(String filePath, final boolean finishActivityWhenDone) { - int rotation = getRotationFromExif(filePath); + protected void setWallpaper(Uri uri, final boolean finishActivityWhenDone) { + int rotation = getRotationFromExif(this, uri); BitmapCropTask cropTask = new BitmapCropTask( - this, filePath, null, rotation, 0, 0, true, false, null); + this, uri, null, rotation, 0, 0, true, false, null); final Point bounds = cropTask.getImageBounds(); Runnable onEndCrop = new Runnable() { public void run() { @@ -352,10 +374,13 @@ public class WallpaperCropActivity extends Activity { getWindowManager()); // Get the crop RectF cropRect = mCropView.getCrop(); + + Point inSize = mCropView.getSourceDimensions(); + int cropRotation = mCropView.getImageRotation(); float cropScale = mCropView.getWidth() / (float) cropRect.width(); - Point inSize = mCropView.getSourceDimensions(); + Matrix rotateMatrix = new Matrix(); rotateMatrix.setRotate(cropRotation); float[] rotatedInSize = new float[] { inSize.x, inSize.y }; @@ -363,6 +388,14 @@ public class WallpaperCropActivity extends Activity { rotatedInSize[0] = Math.abs(rotatedInSize[0]); rotatedInSize[1] = Math.abs(rotatedInSize[1]); + + // due to rounding errors in the cropview renderer the edges can be slightly offset + // therefore we ensure that the boundaries are sanely defined + cropRect.left = Math.max(0, cropRect.left); + cropRect.right = Math.min(rotatedInSize[0], cropRect.right); + cropRect.top = Math.max(0, cropRect.top); + cropRect.bottom = Math.min(rotatedInSize[1], cropRect.bottom); + // ADJUST CROP WIDTH // Extend the crop all the way to the right, for parallax // (or all the way to the left, in RTL) @@ -799,17 +832,28 @@ public class WallpaperCropActivity extends Activity { editor.commit(); suggestWallpaperDimension(getResources(), - sp, getWindowManager(), WallpaperManager.getInstance(this)); + sp, getWindowManager(), WallpaperManager.getInstance(this), true); } static public void suggestWallpaperDimension(Resources res, final SharedPreferences sharedPrefs, WindowManager windowManager, - final WallpaperManager wallpaperManager) { + final WallpaperManager wallpaperManager, boolean fallBackToDefaults) { final Point defaultWallpaperSize = getDefaultWallpaperSize(res, windowManager); // If we have saved a wallpaper width/height, use that instead - int savedWidth = sharedPrefs.getInt(WALLPAPER_WIDTH_KEY, defaultWallpaperSize.x); - int savedHeight = sharedPrefs.getInt(WALLPAPER_HEIGHT_KEY, defaultWallpaperSize.y); + + int savedWidth = sharedPrefs.getInt(WALLPAPER_WIDTH_KEY, -1); + int savedHeight = sharedPrefs.getInt(WALLPAPER_HEIGHT_KEY, -1); + + if (savedWidth == -1 || savedHeight == -1) { + if (!fallBackToDefaults) { + return; + } else { + savedWidth = defaultWallpaperSize.x; + savedHeight = defaultWallpaperSize.y; + } + } + if (savedWidth != wallpaperManager.getDesiredMinimumWidth() || savedHeight != wallpaperManager.getDesiredMinimumHeight()) { wallpaperManager.suggestDesiredDimensions(savedWidth, savedHeight); diff --git a/WallpaperPicker/src/com/android/launcher3/WallpaperPickerActivity.java b/WallpaperPicker/src/com/android/launcher3/WallpaperPickerActivity.java index 013606a50..07285372e 100644 --- a/WallpaperPicker/src/com/android/launcher3/WallpaperPickerActivity.java +++ b/WallpaperPicker/src/com/android/launcher3/WallpaperPickerActivity.java @@ -17,6 +17,7 @@ package com.android.launcher3; import android.animation.LayoutTransition; +import android.annotation.TargetApi; import android.app.ActionBar; import android.app.Activity; import android.app.WallpaperInfo; @@ -61,12 +62,12 @@ import android.view.ViewTreeObserver.OnGlobalLayoutListener; import android.view.WindowManager; import android.view.animation.AccelerateInterpolator; import android.view.animation.DecelerateInterpolator; +import android.widget.ArrayAdapter; import android.widget.BaseAdapter; import android.widget.FrameLayout; import android.widget.HorizontalScrollView; import android.widget.ImageView; import android.widget.LinearLayout; -import android.widget.ListAdapter; import android.widget.Toast; import com.android.photos.BitmapRegionTileSource; @@ -109,6 +110,8 @@ public class WallpaperPickerActivity extends WallpaperCropActivity { public static abstract class WallpaperTileInfo { protected View mView; + public Drawable mThumb; + public void setView(View v) { mView = v; } @@ -194,10 +197,36 @@ public class WallpaperPickerActivity extends WallpaperCropActivity { } } + public static class FileWallpaperInfo extends WallpaperTileInfo { + private File mFile; + + public FileWallpaperInfo(File target, Drawable thumb) { + mFile = target; + mThumb = thumb; + } + @Override + public void onClick(WallpaperPickerActivity a) { + BitmapRegionTileSource.UriBitmapSource bitmapSource = + new BitmapRegionTileSource.UriBitmapSource(a, Uri.fromFile(mFile), 1024); + a.setCropViewTileSource(bitmapSource, false, true, null); + } + @Override + public void onSave(WallpaperPickerActivity a) { + a.setWallpaper(Uri.fromFile(mFile), true); + } + @Override + public boolean isSelectable() { + return true; + } + @Override + public boolean isNamelessWallpaper() { + return true; + } + } + public static class ResourceWallpaperInfo extends WallpaperTileInfo { private Resources mResources; private int mResId; - private Drawable mThumb; public ResourceWallpaperInfo(Resources res, int resId, Drawable thumb) { mResources = res; @@ -237,8 +266,8 @@ public class WallpaperPickerActivity extends WallpaperCropActivity { } } + @TargetApi(Build.VERSION_CODES.KITKAT) public static class DefaultWallpaperInfo extends WallpaperTileInfo { - public Drawable mThumb; public DefaultWallpaperInfo(Drawable thumb) { mThumb = thumb; } @@ -431,9 +460,9 @@ public class WallpaperPickerActivity extends WallpaperCropActivity { }; // Populate the built-in wallpapers - ArrayList<ResourceWallpaperInfo> wallpapers = findBundledWallpapers(); + ArrayList<WallpaperTileInfo> wallpapers = findBundledWallpapers(); mWallpapersView = (LinearLayout) findViewById(R.id.wallpaper_list); - BuiltInWallpapersAdapter ia = new BuiltInWallpapersAdapter(this, wallpapers); + SimpleWallpapersAdapter ia = new SimpleWallpapersAdapter(this, wallpapers); populateWallpapersFromAdapter(mWallpapersView, ia, false); // Populate the saved wallpapers @@ -484,20 +513,6 @@ public class WallpaperPickerActivity extends WallpaperCropActivity { pickImageInfo.setView(pickImageTile); pickImageTile.setOnClickListener(mThumbnailOnClickListener); - // Add a tile for the default wallpaper - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { - DefaultWallpaperInfo defaultWallpaperInfo = getDefaultWallpaper(); - if (defaultWallpaperInfo != null) { - FrameLayout defaultWallpaperTile = (FrameLayout) createImageTileView( - getLayoutInflater(), 0, null, mWallpapersView, defaultWallpaperInfo.mThumb); - setWallpaperItemPaddingToZero(defaultWallpaperTile); - defaultWallpaperTile.setTag(defaultWallpaperInfo); - mWallpapersView.addView(defaultWallpaperTile, 0); - defaultWallpaperTile.setOnClickListener(mThumbnailOnClickListener); - defaultWallpaperInfo.setView(defaultWallpaperTile); - } - } - // Select the first item; wait for a layout pass so that we initialize the dimensions of // cropView or the defaultWallpaperView first mCropView.addOnLayoutChangeListener(new OnLayoutChangeListener() { @@ -674,13 +689,16 @@ public class WallpaperPickerActivity extends WallpaperCropActivity { new String[] { MediaStore.Images.ImageColumns._ID, MediaStore.Images.ImageColumns.DATE_TAKEN}, null, null, MediaStore.Images.ImageColumns.DATE_TAKEN + " DESC LIMIT 1"); + Bitmap thumb = null; - if (cursor.moveToNext()) { - int id = cursor.getInt(0); - thumb = MediaStore.Images.Thumbnails.getThumbnail(getContentResolver(), - id, MediaStore.Images.Thumbnails.MINI_KIND, null); + if (cursor != null) { + if (cursor.moveToNext()) { + int id = cursor.getInt(0); + thumb = MediaStore.Images.Thumbnails.getThumbnail(getContentResolver(), + id, MediaStore.Images.Thumbnails.MINI_KIND, null); + } + cursor.close(); } - cursor.close(); return thumb; } @@ -822,12 +840,26 @@ public class WallpaperPickerActivity extends WallpaperCropActivity { final Context context = this; new AsyncTask<Void, Bitmap, Bitmap>() { protected Bitmap doInBackground(Void...args) { - int rotation = WallpaperCropActivity.getRotationFromExif(context, uri); - return createThumbnail(defaultSize, context, uri, null, null, 0, rotation, false); - + try { + int rotation = WallpaperCropActivity.getRotationFromExif(context, uri); + return createThumbnail(defaultSize, context, uri, null, null, 0, rotation, false); + } catch (SecurityException securityException) { + if (isDestroyed()) { + // Temporarily granted permissions are revoked when the activity + // finishes, potentially resulting in a SecurityException here. + // Even though {@link #isDestroyed} might also return true in different + // situations where the configuration changes, we are fine with + // catching these cases here as well. + cancel(false); + } else { + // otherwise it had a different cause and we throw it further + throw securityException; + } + return null; + } } protected void onPostExecute(Bitmap thumb) { - if (thumb != null) { + if (!isCancelled() && thumb != null) { image.setImageBitmap(thumb); Drawable thumbDrawable = image.getDrawable(); thumbDrawable.setDither(true); @@ -886,27 +918,68 @@ public class WallpaperPickerActivity extends WallpaperCropActivity { v.setOnLongClickListener(mLongClickListener); } - private ArrayList<ResourceWallpaperInfo> findBundledWallpapers() { - ArrayList<ResourceWallpaperInfo> bundledWallpapers = - new ArrayList<ResourceWallpaperInfo>(24); + private ArrayList<WallpaperTileInfo> findBundledWallpapers() { + final PackageManager pm = getPackageManager(); + final ArrayList<WallpaperTileInfo> bundled = new ArrayList<WallpaperTileInfo>(24); + + Partner partner = Partner.get(pm); + if (partner != null) { + final Resources partnerRes = partner.getResources(); + final int resId = partnerRes.getIdentifier(Partner.RES_WALLPAPERS, "array", + partner.getPackageName()); + if (resId != 0) { + addWallpapers(bundled, partnerRes, partner.getPackageName(), resId); + } + + // Add system wallpapers + File systemDir = partner.getWallpaperDirectory(); + if (systemDir != null && systemDir.isDirectory()) { + for (File file : systemDir.listFiles()) { + if (!file.isFile()) { + continue; + } + String name = file.getName(); + int dotPos = name.lastIndexOf('.'); + String extension = ""; + if (dotPos >= -1) { + extension = name.substring(dotPos); + name = name.substring(0, dotPos); + } + + if (name.endsWith("_small")) { + // it is a thumbnail + continue; + } + + File thumbnail = new File(systemDir, name + "_small" + extension); + Bitmap thumb = BitmapFactory.decodeFile(thumbnail.getAbsolutePath()); + if (thumb != null) { + bundled.add(new FileWallpaperInfo(file, new BitmapDrawable(thumb))); + } + } + } + } Pair<ApplicationInfo, Integer> r = getWallpaperArrayResourceId(); if (r != null) { try { Resources wallpaperRes = getPackageManager().getResourcesForApplication(r.first); - bundledWallpapers = addWallpapers(wallpaperRes, r.first.packageName, r.second); + addWallpapers(bundled, wallpaperRes, r.first.packageName, r.second); } catch (PackageManager.NameNotFoundException e) { } } - // Add an entry for the default wallpaper (stored in system resources) - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) { - ResourceWallpaperInfo defaultWallpaperInfo = getPreKKDefaultWallpaperInfo(); + if (partner == null || !partner.hideDefaultWallpaper()) { + // Add an entry for the default wallpaper (stored in system resources) + WallpaperTileInfo defaultWallpaperInfo = + (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) + ? getPreKKDefaultWallpaperInfo() + : getDefaultWallpaper(); if (defaultWallpaperInfo != null) { - bundledWallpapers.add(0, defaultWallpaperInfo); + bundled.add(0, defaultWallpaperInfo); } } - return bundledWallpapers; + return bundled; } private boolean writeImageToFileAsJpeg(File f, Bitmap b) { @@ -924,11 +997,27 @@ public class WallpaperPickerActivity extends WallpaperCropActivity { return false; } + private File getDefaultThumbFile() { + return new File(getFilesDir(), Build.VERSION.SDK_INT + + "_" + DEFAULT_WALLPAPER_THUMBNAIL_FILENAME); + } + + private boolean saveDefaultWallpaperThumb(Bitmap b) { + // Delete old thumbnails. + new File(getFilesDir(), OLD_DEFAULT_WALLPAPER_THUMBNAIL_FILENAME).delete(); + new File(getFilesDir(), DEFAULT_WALLPAPER_THUMBNAIL_FILENAME).delete(); + + for (int i = Build.VERSION_CODES.JELLY_BEAN; i < Build.VERSION.SDK_INT; i++) { + new File(getFilesDir(), i + "_" + DEFAULT_WALLPAPER_THUMBNAIL_FILENAME).delete(); + } + return writeImageToFileAsJpeg(getDefaultThumbFile(), b); + } + private ResourceWallpaperInfo getPreKKDefaultWallpaperInfo() { Resources sysRes = Resources.getSystem(); int resId = sysRes.getIdentifier("default_wallpaper", "drawable", "android"); - File defaultThumbFile = new File(getFilesDir(), DEFAULT_WALLPAPER_THUMBNAIL_FILENAME); + File defaultThumbFile = getDefaultThumbFile(); Bitmap thumb = null; boolean defaultWallpaperExists = false; if (defaultThumbFile.exists()) { @@ -941,7 +1030,7 @@ public class WallpaperPickerActivity extends WallpaperCropActivity { thumb = createThumbnail( defaultThumbSize, this, null, null, sysRes, resId, rotation, false); if (thumb != null) { - defaultWallpaperExists = writeImageToFileAsJpeg(defaultThumbFile, thumb); + defaultWallpaperExists = saveDefaultWallpaperThumb(thumb); } } if (defaultWallpaperExists) { @@ -950,18 +1039,15 @@ public class WallpaperPickerActivity extends WallpaperCropActivity { return null; } + @TargetApi(Build.VERSION_CODES.KITKAT) private DefaultWallpaperInfo getDefaultWallpaper() { - File defaultThumbFile = new File(getFilesDir(), DEFAULT_WALLPAPER_THUMBNAIL_FILENAME); + File defaultThumbFile = getDefaultThumbFile(); Bitmap thumb = null; boolean defaultWallpaperExists = false; if (defaultThumbFile.exists()) { thumb = BitmapFactory.decodeFile(defaultThumbFile.getAbsolutePath()); defaultWallpaperExists = true; } else { - // Delete old thumbnail file, since we had a bug where the thumbnail wasn't being drawn - // before - new File(getFilesDir(), OLD_DEFAULT_WALLPAPER_THUMBNAIL_FILENAME).delete(); - Resources res = getResources(); Point defaultThumbSize = getDefaultThumbnailSize(res); Drawable wallpaperDrawable = WallpaperManager.getInstance(this).getBuiltInDrawable( @@ -975,7 +1061,7 @@ public class WallpaperPickerActivity extends WallpaperCropActivity { c.setBitmap(null); } if (thumb != null) { - defaultWallpaperExists = writeImageToFileAsJpeg(defaultThumbFile, thumb); + defaultWallpaperExists = saveDefaultWallpaperThumb(thumb); } } if (defaultWallpaperExists) { @@ -998,10 +1084,8 @@ public class WallpaperPickerActivity extends WallpaperCropActivity { } } - private ArrayList<ResourceWallpaperInfo> addWallpapers( - Resources res, String packageName, int listResId) { - ArrayList<ResourceWallpaperInfo> bundledWallpapers = - new ArrayList<ResourceWallpaperInfo>(24); + private void addWallpapers(ArrayList<WallpaperTileInfo> known, Resources res, + String packageName, int listResId) { final String[] extras = res.getStringArray(listResId); for (String extra : extras) { int resId = res.getIdentifier(extra, "drawable", packageName); @@ -1011,14 +1095,13 @@ public class WallpaperPickerActivity extends WallpaperCropActivity { if (thumbRes != 0) { ResourceWallpaperInfo wallpaperInfo = new ResourceWallpaperInfo(res, resId, res.getDrawable(thumbRes)); - bundledWallpapers.add(wallpaperInfo); + known.add(wallpaperInfo); // Log.d(TAG, "add: [" + packageName + "]: " + extra + " (" + res + ")"); } } else { Log.e(TAG, "Couldn't find wallpaper " + extra); } } - return bundledWallpapers; } public CropView getCropView() { @@ -1048,37 +1131,24 @@ public class WallpaperPickerActivity extends WallpaperCropActivity { } } - private static class BuiltInWallpapersAdapter extends BaseAdapter implements ListAdapter { - private LayoutInflater mLayoutInflater; - private ArrayList<ResourceWallpaperInfo> mWallpapers; + private static class SimpleWallpapersAdapter extends ArrayAdapter<WallpaperTileInfo> { + private final LayoutInflater mLayoutInflater; - BuiltInWallpapersAdapter(Activity activity, ArrayList<ResourceWallpaperInfo> wallpapers) { + SimpleWallpapersAdapter(Activity activity, ArrayList<WallpaperTileInfo> wallpapers) { + super(activity, R.layout.wallpaper_picker_item, wallpapers); mLayoutInflater = activity.getLayoutInflater(); - mWallpapers = wallpapers; - } - - public int getCount() { - return mWallpapers.size(); - } - - public ResourceWallpaperInfo getItem(int position) { - return mWallpapers.get(position); - } - - public long getItemId(int position) { - return position; } public View getView(int position, View convertView, ViewGroup parent) { - Drawable thumb = mWallpapers.get(position).mThumb; + Drawable thumb = getItem(position).mThumb; if (thumb == null) { Log.e(TAG, "Error decoding thumbnail for wallpaper #" + position); } - return createImageTileView(mLayoutInflater, position, convertView, parent, thumb); + return createImageTileView(mLayoutInflater, convertView, parent, thumb); } } - public static View createImageTileView(LayoutInflater layoutInflater, int position, + public static View createImageTileView(LayoutInflater layoutInflater, View convertView, ViewGroup parent, Drawable thumb) { View view; diff --git a/WallpaperPicker/src/com/android/photos/BitmapRegionTileSource.java b/WallpaperPicker/src/com/android/photos/BitmapRegionTileSource.java index 764156de0..66ece4ff6 100644 --- a/WallpaperPicker/src/com/android/photos/BitmapRegionTileSource.java +++ b/WallpaperPicker/src/com/android/photos/BitmapRegionTileSource.java @@ -283,9 +283,6 @@ public class BitmapRegionTileSource implements TiledImageRenderer.TileSource { } catch (FileNotFoundException e) { Log.e("BitmapRegionTileSource", "Failed to load URI " + mUri, e); return null; - } catch (IOException e) { - Log.e("BitmapRegionTileSource", "Failure while reading URI " + mUri, e); - return null; } } @Override diff --git a/proguard.flags b/proguard.flags index a922e919d..0b28c0ef4 100644 --- a/proguard.flags +++ b/proguard.flags @@ -52,3 +52,8 @@ -keep class com.android.launcher3.MemoryDumpActivity { *; } + +-keep class com.android.launcher3.PreloadIconDrawable { + public float getAnimationProgress(); + public void setAnimationProgress(float); +} diff --git a/res/values-sw340dp-port/dimens.xml b/res/anim/no_anim.xml index e36056570..02b162519 100644 --- a/res/values-sw340dp-port/dimens.xml +++ b/res/anim/no_anim.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2011 The Android Open Source Project +<!-- Copyright (C) 2014 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. @@ -14,7 +14,5 @@ limitations under the License. --> -<resources> -<!-- Clings --> - <dimen name="folderClingMarginTop">70dp</dimen> -</resources> +<alpha xmlns:android="http://schemas.android.com/apk/res/android" + android:duration="417" /> diff --git a/res/anim/task_open_enter.xml b/res/anim/task_open_enter.xml new file mode 100644 index 000000000..3eb191537 --- /dev/null +++ b/res/anim/task_open_enter.xml @@ -0,0 +1,34 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** Copyright 2014, 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. +*/ +--> + +<set xmlns:android="http://schemas.android.com/apk/res/android" + android:background="#ff000000" android:shareInterpolator="false" android:zAdjustment="top"> + + <alpha android:fromAlpha="0" android:toAlpha="1.0" + android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true" + android:interpolator="@interpolator/decelerate_quart" + android:startOffset="0" + android:duration="167"/> + + <translate android:fromYDelta="110%" android:toYDelta="0" + android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true" + android:interpolator="@interpolator/decelerate_quint" + android:startOffset="0" + android:duration="417" /> +</set> diff --git a/res/drawable-hdpi/bg_cling1.png b/res/drawable-hdpi/bg_cling1.png Binary files differdeleted file mode 100644 index 0e1553299..000000000 --- a/res/drawable-hdpi/bg_cling1.png +++ /dev/null diff --git a/res/drawable-hdpi/bg_cling2.png b/res/drawable-hdpi/bg_cling2.png Binary files differdeleted file mode 100644 index e65d9a21c..000000000 --- a/res/drawable-hdpi/bg_cling2.png +++ /dev/null diff --git a/res/drawable-hdpi/bg_cling3.png b/res/drawable-hdpi/bg_cling3.png Binary files differdeleted file mode 100644 index ea71fbdb3..000000000 --- a/res/drawable-hdpi/bg_cling3.png +++ /dev/null diff --git a/res/drawable-hdpi/bg_cling4.png b/res/drawable-hdpi/bg_cling4.png Binary files differdeleted file mode 100644 index 94036677e..000000000 --- a/res/drawable-hdpi/bg_cling4.png +++ /dev/null diff --git a/res/drawable-hdpi/cling.9.png b/res/drawable-hdpi/cling.9.png Binary files differdeleted file mode 100644 index 36fbfc8b6..000000000 --- a/res/drawable-hdpi/cling.9.png +++ /dev/null diff --git a/res/drawable-hdpi/cling_arrow_down.png b/res/drawable-hdpi/cling_arrow_down.png Binary files differdeleted file mode 100644 index 4f521eadc..000000000 --- a/res/drawable-hdpi/cling_arrow_down.png +++ /dev/null diff --git a/res/drawable-hdpi/cling_arrow_left.png b/res/drawable-hdpi/cling_arrow_left.png Binary files differdeleted file mode 100644 index 13764c9e2..000000000 --- a/res/drawable-hdpi/cling_arrow_left.png +++ /dev/null diff --git a/res/drawable-hdpi/cling_arrow_right.png b/res/drawable-hdpi/cling_arrow_right.png Binary files differdeleted file mode 100644 index be522441d..000000000 --- a/res/drawable-hdpi/cling_arrow_right.png +++ /dev/null diff --git a/res/drawable-hdpi/cling_arrow_up.png b/res/drawable-hdpi/cling_arrow_up.png Binary files differdeleted file mode 100644 index 83b5b3783..000000000 --- a/res/drawable-hdpi/cling_arrow_up.png +++ /dev/null diff --git a/res/drawable-hdpi/cling_bg.9.png b/res/drawable-hdpi/cling_bg.9.png Binary files differnew file mode 100644 index 000000000..e173ba595 --- /dev/null +++ b/res/drawable-hdpi/cling_bg.9.png diff --git a/res/drawable-hdpi/cling_button.9.png b/res/drawable-hdpi/cling_button.9.png Binary files differdeleted file mode 100644 index e30838241..000000000 --- a/res/drawable-hdpi/cling_button.9.png +++ /dev/null diff --git a/res/drawable-hdpi/cling_button_pressed.9.png b/res/drawable-hdpi/cling_button_pressed.9.png Binary files differdeleted file mode 100644 index 4f9ca6f7a..000000000 --- a/res/drawable-hdpi/cling_button_pressed.9.png +++ /dev/null diff --git a/res/drawable-hdpi/custom_content_page.png b/res/drawable-hdpi/custom_content_page.png Binary files differdeleted file mode 100644 index 9eef50c92..000000000 --- a/res/drawable-hdpi/custom_content_page.png +++ /dev/null diff --git a/res/drawable-hdpi/focused_bg.9.png b/res/drawable-hdpi/focused_bg.9.png Binary files differdeleted file mode 100644 index 2925ae858..000000000 --- a/res/drawable-hdpi/focused_bg.9.png +++ /dev/null diff --git a/res/drawable-hdpi/ic_allapps.png b/res/drawable-hdpi/ic_allapps.png Binary files differindex e7677d5d2..b98e65f99 100644 --- a/res/drawable-hdpi/ic_allapps.png +++ b/res/drawable-hdpi/ic_allapps.png diff --git a/res/drawable-hdpi/ic_allapps_pressed.png b/res/drawable-hdpi/ic_allapps_pressed.png Binary files differindex 863eebaa5..b7eaa675f 100644 --- a/res/drawable-hdpi/ic_allapps_pressed.png +++ b/res/drawable-hdpi/ic_allapps_pressed.png diff --git a/res/drawable-hdpi/ic_pageindicator_add.png b/res/drawable-hdpi/ic_pageindicator_add.png Binary files differindex c37d622e5..ab0e5dbd5 100644 --- a/res/drawable-hdpi/ic_pageindicator_add.png +++ b/res/drawable-hdpi/ic_pageindicator_add.png diff --git a/res/drawable-hdpi/ic_pageindicator_current.png b/res/drawable-hdpi/ic_pageindicator_current.png Binary files differindex aac8d406d..2e841f5f5 100644 --- a/res/drawable-hdpi/ic_pageindicator_current.png +++ b/res/drawable-hdpi/ic_pageindicator_current.png diff --git a/res/drawable-hdpi/ic_pageindicator_default.png b/res/drawable-hdpi/ic_pageindicator_default.png Binary files differindex bafd94b87..07ab94865 100644 --- a/res/drawable-hdpi/ic_pageindicator_default.png +++ b/res/drawable-hdpi/ic_pageindicator_default.png diff --git a/res/drawable-hdpi/ic_setting.png b/res/drawable-hdpi/ic_setting.png Binary files differindex 3f5bc43fd..1c12a5b80 100644 --- a/res/drawable-hdpi/ic_setting.png +++ b/res/drawable-hdpi/ic_setting.png diff --git a/res/drawable-hdpi/ic_setting_pressed.png b/res/drawable-hdpi/ic_setting_pressed.png Binary files differindex 9201064cf..d5b5ca204 100644 --- a/res/drawable-hdpi/ic_setting_pressed.png +++ b/res/drawable-hdpi/ic_setting_pressed.png diff --git a/res/drawable-hdpi/ic_wallpaper.png b/res/drawable-hdpi/ic_wallpaper.png Binary files differindex 5e5d1186b..34d594336 100644 --- a/res/drawable-hdpi/ic_wallpaper.png +++ b/res/drawable-hdpi/ic_wallpaper.png diff --git a/res/drawable-hdpi/ic_wallpaper_pressed.png b/res/drawable-hdpi/ic_wallpaper_pressed.png Binary files differindex d104e5770..1588ce717 100644 --- a/res/drawable-hdpi/ic_wallpaper_pressed.png +++ b/res/drawable-hdpi/ic_wallpaper_pressed.png diff --git a/res/drawable-hdpi/ic_widget.png b/res/drawable-hdpi/ic_widget.png Binary files differindex 8c57af0de..ed7e1ca0d 100644 --- a/res/drawable-hdpi/ic_widget.png +++ b/res/drawable-hdpi/ic_widget.png diff --git a/res/drawable-hdpi/ic_widget_pressed.png b/res/drawable-hdpi/ic_widget_pressed.png Binary files differindex 081f9f9ce..19d6feded 100644 --- a/res/drawable-hdpi/ic_widget_pressed.png +++ b/res/drawable-hdpi/ic_widget_pressed.png diff --git a/res/drawable-hdpi/page_hover_left.9.png b/res/drawable-hdpi/page_hover_left.9.png Binary files differnew file mode 100644 index 000000000..cc029d816 --- /dev/null +++ b/res/drawable-hdpi/page_hover_left.9.png diff --git a/res/drawable-hdpi/page_hover_left_active.9.png b/res/drawable-hdpi/page_hover_left_active.9.png Binary files differnew file mode 100644 index 000000000..20c91a0fd --- /dev/null +++ b/res/drawable-hdpi/page_hover_left_active.9.png diff --git a/res/drawable-hdpi/page_hover_left_holo.9.png b/res/drawable-hdpi/page_hover_left_holo.9.png Binary files differdeleted file mode 100644 index 8a1aa5fe8..000000000 --- a/res/drawable-hdpi/page_hover_left_holo.9.png +++ /dev/null diff --git a/res/drawable-hdpi/page_hover_right.9.png b/res/drawable-hdpi/page_hover_right.9.png Binary files differnew file mode 100644 index 000000000..a42822ad8 --- /dev/null +++ b/res/drawable-hdpi/page_hover_right.9.png diff --git a/res/drawable-hdpi/page_hover_right_active.9.png b/res/drawable-hdpi/page_hover_right_active.9.png Binary files differnew file mode 100644 index 000000000..523fafd6d --- /dev/null +++ b/res/drawable-hdpi/page_hover_right_active.9.png diff --git a/res/drawable-hdpi/page_hover_right_holo.9.png b/res/drawable-hdpi/page_hover_right_holo.9.png Binary files differdeleted file mode 100644 index abf8f5173..000000000 --- a/res/drawable-hdpi/page_hover_right_holo.9.png +++ /dev/null diff --git a/res/drawable-hdpi/quantum_panel.9.png b/res/drawable-hdpi/quantum_panel.9.png Binary files differnew file mode 100644 index 000000000..b4ac9c0a0 --- /dev/null +++ b/res/drawable-hdpi/quantum_panel.9.png diff --git a/res/drawable-hdpi/quantum_panel_dark.9.png b/res/drawable-hdpi/quantum_panel_dark.9.png Binary files differnew file mode 100644 index 000000000..abaf23026 --- /dev/null +++ b/res/drawable-hdpi/quantum_panel_dark.9.png diff --git a/res/drawable-hdpi/screenpanel.9.png b/res/drawable-hdpi/screenpanel.9.png Binary files differindex 36e7dfd9c..f7ae01162 100644 --- a/res/drawable-hdpi/screenpanel.9.png +++ b/res/drawable-hdpi/screenpanel.9.png diff --git a/res/drawable-hdpi/screenpanel_hover.9.png b/res/drawable-hdpi/screenpanel_hover.9.png Binary files differindex 0fed7c9d8..ac8e83dbd 100644 --- a/res/drawable-hdpi/screenpanel_hover.9.png +++ b/res/drawable-hdpi/screenpanel_hover.9.png diff --git a/res/drawable-hdpi/virtual_preload.9.png b/res/drawable-hdpi/virtual_preload.9.png Binary files differnew file mode 100644 index 000000000..71e53263e --- /dev/null +++ b/res/drawable-hdpi/virtual_preload.9.png diff --git a/res/drawable-hdpi/virtual_preload_folder.9.png b/res/drawable-hdpi/virtual_preload_folder.9.png Binary files differnew file mode 100644 index 000000000..ece322669 --- /dev/null +++ b/res/drawable-hdpi/virtual_preload_folder.9.png diff --git a/res/drawable-hdpi/widget_container_holo.9.png b/res/drawable-hdpi/widget_container_holo.9.png Binary files differdeleted file mode 100644 index 8c15a7c86..000000000 --- a/res/drawable-hdpi/widget_container_holo.9.png +++ /dev/null diff --git a/res/drawable-land-hdpi/bg_cling1.png b/res/drawable-land-hdpi/bg_cling1.png Binary files differdeleted file mode 100644 index 7123c5ca7..000000000 --- a/res/drawable-land-hdpi/bg_cling1.png +++ /dev/null diff --git a/res/drawable-land-hdpi/bg_cling2.png b/res/drawable-land-hdpi/bg_cling2.png Binary files differdeleted file mode 100644 index 889b6274e..000000000 --- a/res/drawable-land-hdpi/bg_cling2.png +++ /dev/null diff --git a/res/drawable-land-hdpi/bg_cling3.png b/res/drawable-land-hdpi/bg_cling3.png Binary files differdeleted file mode 100644 index 4ff338c13..000000000 --- a/res/drawable-land-hdpi/bg_cling3.png +++ /dev/null diff --git a/res/drawable-land-mdpi/bg_cling1.png b/res/drawable-land-mdpi/bg_cling1.png Binary files differdeleted file mode 100644 index f5faeb439..000000000 --- a/res/drawable-land-mdpi/bg_cling1.png +++ /dev/null diff --git a/res/drawable-land-mdpi/bg_cling2.png b/res/drawable-land-mdpi/bg_cling2.png Binary files differdeleted file mode 100644 index 963967d30..000000000 --- a/res/drawable-land-mdpi/bg_cling2.png +++ /dev/null diff --git a/res/drawable-land-mdpi/bg_cling3.png b/res/drawable-land-mdpi/bg_cling3.png Binary files differdeleted file mode 100644 index 921831af9..000000000 --- a/res/drawable-land-mdpi/bg_cling3.png +++ /dev/null diff --git a/res/drawable-land-xhdpi/bg_cling1.png b/res/drawable-land-xhdpi/bg_cling1.png Binary files differdeleted file mode 100644 index 2282117ca..000000000 --- a/res/drawable-land-xhdpi/bg_cling1.png +++ /dev/null diff --git a/res/drawable-land-xhdpi/bg_cling2.png b/res/drawable-land-xhdpi/bg_cling2.png Binary files differdeleted file mode 100644 index 5243889be..000000000 --- a/res/drawable-land-xhdpi/bg_cling2.png +++ /dev/null diff --git a/res/drawable-land-xhdpi/bg_cling3.png b/res/drawable-land-xhdpi/bg_cling3.png Binary files differdeleted file mode 100644 index 08475f732..000000000 --- a/res/drawable-land-xhdpi/bg_cling3.png +++ /dev/null diff --git a/res/drawable-land-xxhdpi/bg_cling1.png b/res/drawable-land-xxhdpi/bg_cling1.png Binary files differdeleted file mode 100644 index 78943f01c..000000000 --- a/res/drawable-land-xxhdpi/bg_cling1.png +++ /dev/null diff --git a/res/drawable-land-xxhdpi/bg_cling2.png b/res/drawable-land-xxhdpi/bg_cling2.png Binary files differdeleted file mode 100644 index 98b65682b..000000000 --- a/res/drawable-land-xxhdpi/bg_cling2.png +++ /dev/null diff --git a/res/drawable-land-xxhdpi/bg_cling3.png b/res/drawable-land-xxhdpi/bg_cling3.png Binary files differdeleted file mode 100644 index e249fe598..000000000 --- a/res/drawable-land-xxhdpi/bg_cling3.png +++ /dev/null diff --git a/res/drawable-mdpi/bg_cling1.png b/res/drawable-mdpi/bg_cling1.png Binary files differdeleted file mode 100644 index f284412a7..000000000 --- a/res/drawable-mdpi/bg_cling1.png +++ /dev/null diff --git a/res/drawable-mdpi/bg_cling2.png b/res/drawable-mdpi/bg_cling2.png Binary files differdeleted file mode 100644 index 0052dc29d..000000000 --- a/res/drawable-mdpi/bg_cling2.png +++ /dev/null diff --git a/res/drawable-mdpi/bg_cling3.png b/res/drawable-mdpi/bg_cling3.png Binary files differdeleted file mode 100644 index fabdf7a0d..000000000 --- a/res/drawable-mdpi/bg_cling3.png +++ /dev/null diff --git a/res/drawable-mdpi/bg_cling4.png b/res/drawable-mdpi/bg_cling4.png Binary files differdeleted file mode 100644 index 2f152f4db..000000000 --- a/res/drawable-mdpi/bg_cling4.png +++ /dev/null diff --git a/res/drawable-mdpi/bg_cling5.png b/res/drawable-mdpi/bg_cling5.png Binary files differdeleted file mode 100644 index e094809b4..000000000 --- a/res/drawable-mdpi/bg_cling5.png +++ /dev/null diff --git a/res/drawable-mdpi/cling.9.png b/res/drawable-mdpi/cling.9.png Binary files differdeleted file mode 100644 index 4c0f139ee..000000000 --- a/res/drawable-mdpi/cling.9.png +++ /dev/null diff --git a/res/drawable-mdpi/cling_arrow_down.png b/res/drawable-mdpi/cling_arrow_down.png Binary files differdeleted file mode 100644 index 58e66fbb2..000000000 --- a/res/drawable-mdpi/cling_arrow_down.png +++ /dev/null diff --git a/res/drawable-mdpi/cling_arrow_left.png b/res/drawable-mdpi/cling_arrow_left.png Binary files differdeleted file mode 100644 index 023c71705..000000000 --- a/res/drawable-mdpi/cling_arrow_left.png +++ /dev/null diff --git a/res/drawable-mdpi/cling_arrow_right.png b/res/drawable-mdpi/cling_arrow_right.png Binary files differdeleted file mode 100644 index cf0eb1047..000000000 --- a/res/drawable-mdpi/cling_arrow_right.png +++ /dev/null diff --git a/res/drawable-mdpi/cling_arrow_up.png b/res/drawable-mdpi/cling_arrow_up.png Binary files differdeleted file mode 100644 index 9b0e6b7ae..000000000 --- a/res/drawable-mdpi/cling_arrow_up.png +++ /dev/null diff --git a/res/drawable-mdpi/cling_bg.9.png b/res/drawable-mdpi/cling_bg.9.png Binary files differnew file mode 100644 index 000000000..fc49c891c --- /dev/null +++ b/res/drawable-mdpi/cling_bg.9.png diff --git a/res/drawable-mdpi/cling_button.9.png b/res/drawable-mdpi/cling_button.9.png Binary files differdeleted file mode 100644 index a0b6f9735..000000000 --- a/res/drawable-mdpi/cling_button.9.png +++ /dev/null diff --git a/res/drawable-mdpi/cling_button_pressed.9.png b/res/drawable-mdpi/cling_button_pressed.9.png Binary files differdeleted file mode 100644 index 986e66944..000000000 --- a/res/drawable-mdpi/cling_button_pressed.9.png +++ /dev/null diff --git a/res/drawable-mdpi/custom_content_page.png b/res/drawable-mdpi/custom_content_page.png Binary files differdeleted file mode 100644 index cc4005ded..000000000 --- a/res/drawable-mdpi/custom_content_page.png +++ /dev/null diff --git a/res/drawable-mdpi/focused_bg.9.png b/res/drawable-mdpi/focused_bg.9.png Binary files differdeleted file mode 100644 index 89c29ac51..000000000 --- a/res/drawable-mdpi/focused_bg.9.png +++ /dev/null diff --git a/res/drawable-mdpi/ic_allapps.png b/res/drawable-mdpi/ic_allapps.png Binary files differindex e0fd9c07a..f4106734a 100644 --- a/res/drawable-mdpi/ic_allapps.png +++ b/res/drawable-mdpi/ic_allapps.png diff --git a/res/drawable-mdpi/ic_allapps_pressed.png b/res/drawable-mdpi/ic_allapps_pressed.png Binary files differindex 3bd87b187..aa4f913b9 100644 --- a/res/drawable-mdpi/ic_allapps_pressed.png +++ b/res/drawable-mdpi/ic_allapps_pressed.png diff --git a/res/drawable-mdpi/ic_pageindicator_add.png b/res/drawable-mdpi/ic_pageindicator_add.png Binary files differindex 8e05e64f0..11659a3b2 100644 --- a/res/drawable-mdpi/ic_pageindicator_add.png +++ b/res/drawable-mdpi/ic_pageindicator_add.png diff --git a/res/drawable-mdpi/ic_pageindicator_current.png b/res/drawable-mdpi/ic_pageindicator_current.png Binary files differindex ab5f4c82f..08f43b4c1 100644 --- a/res/drawable-mdpi/ic_pageindicator_current.png +++ b/res/drawable-mdpi/ic_pageindicator_current.png diff --git a/res/drawable-mdpi/ic_pageindicator_default.png b/res/drawable-mdpi/ic_pageindicator_default.png Binary files differindex c919ee835..635be4a37 100644 --- a/res/drawable-mdpi/ic_pageindicator_default.png +++ b/res/drawable-mdpi/ic_pageindicator_default.png diff --git a/res/drawable-mdpi/ic_setting.png b/res/drawable-mdpi/ic_setting.png Binary files differindex 1e7645953..c614e9183 100644 --- a/res/drawable-mdpi/ic_setting.png +++ b/res/drawable-mdpi/ic_setting.png diff --git a/res/drawable-mdpi/ic_setting_pressed.png b/res/drawable-mdpi/ic_setting_pressed.png Binary files differindex d7aca18e1..61e574ad1 100644 --- a/res/drawable-mdpi/ic_setting_pressed.png +++ b/res/drawable-mdpi/ic_setting_pressed.png diff --git a/res/drawable-mdpi/ic_wallpaper.png b/res/drawable-mdpi/ic_wallpaper.png Binary files differindex 333a206e2..8f2a00a3f 100644 --- a/res/drawable-mdpi/ic_wallpaper.png +++ b/res/drawable-mdpi/ic_wallpaper.png diff --git a/res/drawable-mdpi/ic_wallpaper_pressed.png b/res/drawable-mdpi/ic_wallpaper_pressed.png Binary files differindex 273c48b3a..aa598c3e2 100644 --- a/res/drawable-mdpi/ic_wallpaper_pressed.png +++ b/res/drawable-mdpi/ic_wallpaper_pressed.png diff --git a/res/drawable-mdpi/ic_widget.png b/res/drawable-mdpi/ic_widget.png Binary files differindex 5f974c28c..1bd393503 100644 --- a/res/drawable-mdpi/ic_widget.png +++ b/res/drawable-mdpi/ic_widget.png diff --git a/res/drawable-mdpi/ic_widget_pressed.png b/res/drawable-mdpi/ic_widget_pressed.png Binary files differindex 0a3e8838f..9b690d99b 100644 --- a/res/drawable-mdpi/ic_widget_pressed.png +++ b/res/drawable-mdpi/ic_widget_pressed.png diff --git a/res/drawable-mdpi/page_hover_left.9.png b/res/drawable-mdpi/page_hover_left.9.png Binary files differnew file mode 100644 index 000000000..2bbf42807 --- /dev/null +++ b/res/drawable-mdpi/page_hover_left.9.png diff --git a/res/drawable-mdpi/page_hover_left_active.9.png b/res/drawable-mdpi/page_hover_left_active.9.png Binary files differnew file mode 100644 index 000000000..bf70f3601 --- /dev/null +++ b/res/drawable-mdpi/page_hover_left_active.9.png diff --git a/res/drawable-mdpi/page_hover_left_holo.9.png b/res/drawable-mdpi/page_hover_left_holo.9.png Binary files differdeleted file mode 100644 index 561d3cd31..000000000 --- a/res/drawable-mdpi/page_hover_left_holo.9.png +++ /dev/null diff --git a/res/drawable-mdpi/page_hover_right.9.png b/res/drawable-mdpi/page_hover_right.9.png Binary files differnew file mode 100644 index 000000000..4bafd0f71 --- /dev/null +++ b/res/drawable-mdpi/page_hover_right.9.png diff --git a/res/drawable-mdpi/page_hover_right_active.9.png b/res/drawable-mdpi/page_hover_right_active.9.png Binary files differnew file mode 100644 index 000000000..4aaa0148e --- /dev/null +++ b/res/drawable-mdpi/page_hover_right_active.9.png diff --git a/res/drawable-mdpi/page_hover_right_holo.9.png b/res/drawable-mdpi/page_hover_right_holo.9.png Binary files differdeleted file mode 100644 index 2681f23f0..000000000 --- a/res/drawable-mdpi/page_hover_right_holo.9.png +++ /dev/null diff --git a/res/drawable-mdpi/quantum_panel.9.png b/res/drawable-mdpi/quantum_panel.9.png Binary files differnew file mode 100644 index 000000000..c5a6eb735 --- /dev/null +++ b/res/drawable-mdpi/quantum_panel.9.png diff --git a/res/drawable-mdpi/quantum_panel_dark.9.png b/res/drawable-mdpi/quantum_panel_dark.9.png Binary files differnew file mode 100644 index 000000000..7728a7268 --- /dev/null +++ b/res/drawable-mdpi/quantum_panel_dark.9.png diff --git a/res/drawable-mdpi/screenpanel.9.png b/res/drawable-mdpi/screenpanel.9.png Binary files differindex 4de3017f5..c2779fcf3 100644 --- a/res/drawable-mdpi/screenpanel.9.png +++ b/res/drawable-mdpi/screenpanel.9.png diff --git a/res/drawable-mdpi/screenpanel_hover.9.png b/res/drawable-mdpi/screenpanel_hover.9.png Binary files differindex 7dd885860..70b30785f 100644 --- a/res/drawable-mdpi/screenpanel_hover.9.png +++ b/res/drawable-mdpi/screenpanel_hover.9.png diff --git a/res/drawable-mdpi/virtual_preload.9.png b/res/drawable-mdpi/virtual_preload.9.png Binary files differnew file mode 100644 index 000000000..a3c75192d --- /dev/null +++ b/res/drawable-mdpi/virtual_preload.9.png diff --git a/res/drawable-mdpi/virtual_preload_folder.9.png b/res/drawable-mdpi/virtual_preload_folder.9.png Binary files differnew file mode 100644 index 000000000..fa2f1313d --- /dev/null +++ b/res/drawable-mdpi/virtual_preload_folder.9.png diff --git a/res/drawable-mdpi/widget_container_holo.9.png b/res/drawable-mdpi/widget_container_holo.9.png Binary files differdeleted file mode 100644 index db24457d6..000000000 --- a/res/drawable-mdpi/widget_container_holo.9.png +++ /dev/null diff --git a/res/drawable-nodpi/ic_migration.png b/res/drawable-nodpi/ic_migration.png Binary files differnew file mode 100644 index 000000000..c282cd283 --- /dev/null +++ b/res/drawable-nodpi/ic_migration.png diff --git a/res/drawable-xhdpi/bg_cling1.png b/res/drawable-xhdpi/bg_cling1.png Binary files differdeleted file mode 100644 index b71351a32..000000000 --- a/res/drawable-xhdpi/bg_cling1.png +++ /dev/null diff --git a/res/drawable-xhdpi/bg_cling2.png b/res/drawable-xhdpi/bg_cling2.png Binary files differdeleted file mode 100644 index ad78dfeb0..000000000 --- a/res/drawable-xhdpi/bg_cling2.png +++ /dev/null diff --git a/res/drawable-xhdpi/bg_cling3.png b/res/drawable-xhdpi/bg_cling3.png Binary files differdeleted file mode 100644 index ae04195c4..000000000 --- a/res/drawable-xhdpi/bg_cling3.png +++ /dev/null diff --git a/res/drawable-xhdpi/bg_cling4.png b/res/drawable-xhdpi/bg_cling4.png Binary files differdeleted file mode 100644 index f4bb83e39..000000000 --- a/res/drawable-xhdpi/bg_cling4.png +++ /dev/null diff --git a/res/drawable-xhdpi/cling.9.png b/res/drawable-xhdpi/cling.9.png Binary files differdeleted file mode 100644 index 1cb468159..000000000 --- a/res/drawable-xhdpi/cling.9.png +++ /dev/null diff --git a/res/drawable-xhdpi/cling_arrow_down.png b/res/drawable-xhdpi/cling_arrow_down.png Binary files differdeleted file mode 100644 index ee1093340..000000000 --- a/res/drawable-xhdpi/cling_arrow_down.png +++ /dev/null diff --git a/res/drawable-xhdpi/cling_arrow_left.png b/res/drawable-xhdpi/cling_arrow_left.png Binary files differdeleted file mode 100644 index cffbcf3ce..000000000 --- a/res/drawable-xhdpi/cling_arrow_left.png +++ /dev/null diff --git a/res/drawable-xhdpi/cling_arrow_right.png b/res/drawable-xhdpi/cling_arrow_right.png Binary files differdeleted file mode 100644 index d880d67f0..000000000 --- a/res/drawable-xhdpi/cling_arrow_right.png +++ /dev/null diff --git a/res/drawable-xhdpi/cling_arrow_up.png b/res/drawable-xhdpi/cling_arrow_up.png Binary files differdeleted file mode 100644 index fd2c60c31..000000000 --- a/res/drawable-xhdpi/cling_arrow_up.png +++ /dev/null diff --git a/res/drawable-xhdpi/cling_bg.9.png b/res/drawable-xhdpi/cling_bg.9.png Binary files differnew file mode 100644 index 000000000..4db356f25 --- /dev/null +++ b/res/drawable-xhdpi/cling_bg.9.png diff --git a/res/drawable-xhdpi/cling_button.9.png b/res/drawable-xhdpi/cling_button.9.png Binary files differdeleted file mode 100644 index 4192563b5..000000000 --- a/res/drawable-xhdpi/cling_button.9.png +++ /dev/null diff --git a/res/drawable-xhdpi/cling_button_pressed.9.png b/res/drawable-xhdpi/cling_button_pressed.9.png Binary files differdeleted file mode 100644 index d3ce46977..000000000 --- a/res/drawable-xhdpi/cling_button_pressed.9.png +++ /dev/null diff --git a/res/drawable-xhdpi/custom_content_page.png b/res/drawable-xhdpi/custom_content_page.png Binary files differdeleted file mode 100644 index e1da91c61..000000000 --- a/res/drawable-xhdpi/custom_content_page.png +++ /dev/null diff --git a/res/drawable-xhdpi/focused_bg.9.png b/res/drawable-xhdpi/focused_bg.9.png Binary files differdeleted file mode 100644 index 197a26988..000000000 --- a/res/drawable-xhdpi/focused_bg.9.png +++ /dev/null diff --git a/res/drawable-xhdpi/ic_allapps.png b/res/drawable-xhdpi/ic_allapps.png Binary files differindex f71964c2d..ff3d82372 100644 --- a/res/drawable-xhdpi/ic_allapps.png +++ b/res/drawable-xhdpi/ic_allapps.png diff --git a/res/drawable-xhdpi/ic_allapps_pressed.png b/res/drawable-xhdpi/ic_allapps_pressed.png Binary files differindex d678f027e..5f188f633 100644 --- a/res/drawable-xhdpi/ic_allapps_pressed.png +++ b/res/drawable-xhdpi/ic_allapps_pressed.png diff --git a/res/drawable-xhdpi/ic_pageindicator_add.png b/res/drawable-xhdpi/ic_pageindicator_add.png Binary files differindex 28e164b23..af1da2d42 100644 --- a/res/drawable-xhdpi/ic_pageindicator_add.png +++ b/res/drawable-xhdpi/ic_pageindicator_add.png diff --git a/res/drawable-xhdpi/ic_pageindicator_current.png b/res/drawable-xhdpi/ic_pageindicator_current.png Binary files differindex aed3d7172..0e9a52f6d 100644 --- a/res/drawable-xhdpi/ic_pageindicator_current.png +++ b/res/drawable-xhdpi/ic_pageindicator_current.png diff --git a/res/drawable-xhdpi/ic_pageindicator_default.png b/res/drawable-xhdpi/ic_pageindicator_default.png Binary files differindex 0887416f0..d0f14cdfb 100644 --- a/res/drawable-xhdpi/ic_pageindicator_default.png +++ b/res/drawable-xhdpi/ic_pageindicator_default.png diff --git a/res/drawable-xhdpi/ic_setting.png b/res/drawable-xhdpi/ic_setting.png Binary files differindex 6f06bcfd9..3a7310b7c 100644 --- a/res/drawable-xhdpi/ic_setting.png +++ b/res/drawable-xhdpi/ic_setting.png diff --git a/res/drawable-xhdpi/ic_setting_pressed.png b/res/drawable-xhdpi/ic_setting_pressed.png Binary files differindex bca8ccdd0..005d49c8c 100644 --- a/res/drawable-xhdpi/ic_setting_pressed.png +++ b/res/drawable-xhdpi/ic_setting_pressed.png diff --git a/res/drawable-xhdpi/ic_wallpaper.png b/res/drawable-xhdpi/ic_wallpaper.png Binary files differindex 41dc000fd..d2bf246ee 100644 --- a/res/drawable-xhdpi/ic_wallpaper.png +++ b/res/drawable-xhdpi/ic_wallpaper.png diff --git a/res/drawable-xhdpi/ic_wallpaper_pressed.png b/res/drawable-xhdpi/ic_wallpaper_pressed.png Binary files differindex ffff0531d..5a9b84d7d 100644 --- a/res/drawable-xhdpi/ic_wallpaper_pressed.png +++ b/res/drawable-xhdpi/ic_wallpaper_pressed.png diff --git a/res/drawable-xhdpi/ic_widget.png b/res/drawable-xhdpi/ic_widget.png Binary files differindex 47dcdd14f..cf6be8173 100644 --- a/res/drawable-xhdpi/ic_widget.png +++ b/res/drawable-xhdpi/ic_widget.png diff --git a/res/drawable-xhdpi/ic_widget_pressed.png b/res/drawable-xhdpi/ic_widget_pressed.png Binary files differindex 8bb387b88..633c9c648 100644 --- a/res/drawable-xhdpi/ic_widget_pressed.png +++ b/res/drawable-xhdpi/ic_widget_pressed.png diff --git a/res/drawable-xhdpi/page_hover_left.9.png b/res/drawable-xhdpi/page_hover_left.9.png Binary files differnew file mode 100644 index 000000000..a2b9b65d7 --- /dev/null +++ b/res/drawable-xhdpi/page_hover_left.9.png diff --git a/res/drawable-xhdpi/page_hover_left_active.9.png b/res/drawable-xhdpi/page_hover_left_active.9.png Binary files differnew file mode 100644 index 000000000..ba9478ece --- /dev/null +++ b/res/drawable-xhdpi/page_hover_left_active.9.png diff --git a/res/drawable-xhdpi/page_hover_left_holo.9.png b/res/drawable-xhdpi/page_hover_left_holo.9.png Binary files differdeleted file mode 100644 index 4972a2eeb..000000000 --- a/res/drawable-xhdpi/page_hover_left_holo.9.png +++ /dev/null diff --git a/res/drawable-xhdpi/page_hover_right.9.png b/res/drawable-xhdpi/page_hover_right.9.png Binary files differnew file mode 100644 index 000000000..1243ea9ec --- /dev/null +++ b/res/drawable-xhdpi/page_hover_right.9.png diff --git a/res/drawable-xhdpi/page_hover_right_active.9.png b/res/drawable-xhdpi/page_hover_right_active.9.png Binary files differnew file mode 100644 index 000000000..582261c9b --- /dev/null +++ b/res/drawable-xhdpi/page_hover_right_active.9.png diff --git a/res/drawable-xhdpi/page_hover_right_holo.9.png b/res/drawable-xhdpi/page_hover_right_holo.9.png Binary files differdeleted file mode 100644 index b99461f69..000000000 --- a/res/drawable-xhdpi/page_hover_right_holo.9.png +++ /dev/null diff --git a/res/drawable-xhdpi/quantum_panel.9.png b/res/drawable-xhdpi/quantum_panel.9.png Binary files differnew file mode 100644 index 000000000..1797ad500 --- /dev/null +++ b/res/drawable-xhdpi/quantum_panel.9.png diff --git a/res/drawable-xhdpi/quantum_panel_dark.9.png b/res/drawable-xhdpi/quantum_panel_dark.9.png Binary files differnew file mode 100644 index 000000000..4c1868b55 --- /dev/null +++ b/res/drawable-xhdpi/quantum_panel_dark.9.png diff --git a/res/drawable-xhdpi/screenpanel.9.png b/res/drawable-xhdpi/screenpanel.9.png Binary files differindex b4b828d3e..53a781206 100644 --- a/res/drawable-xhdpi/screenpanel.9.png +++ b/res/drawable-xhdpi/screenpanel.9.png diff --git a/res/drawable-xhdpi/screenpanel_hover.9.png b/res/drawable-xhdpi/screenpanel_hover.9.png Binary files differindex 251bf2085..a2e200f13 100644 --- a/res/drawable-xhdpi/screenpanel_hover.9.png +++ b/res/drawable-xhdpi/screenpanel_hover.9.png diff --git a/res/drawable-xhdpi/virtual_preload.9.png b/res/drawable-xhdpi/virtual_preload.9.png Binary files differnew file mode 100644 index 000000000..d2c3fea9b --- /dev/null +++ b/res/drawable-xhdpi/virtual_preload.9.png diff --git a/res/drawable-xhdpi/virtual_preload_folder.9.png b/res/drawable-xhdpi/virtual_preload_folder.9.png Binary files differnew file mode 100644 index 000000000..1f9202b41 --- /dev/null +++ b/res/drawable-xhdpi/virtual_preload_folder.9.png diff --git a/res/drawable-xhdpi/widget_container_holo.9.png b/res/drawable-xhdpi/widget_container_holo.9.png Binary files differdeleted file mode 100644 index 1313fe70d..000000000 --- a/res/drawable-xhdpi/widget_container_holo.9.png +++ /dev/null diff --git a/res/drawable-xxhdpi/apps_customize_bg.png b/res/drawable-xxhdpi/apps_customize_bg.png Binary files differnew file mode 100644 index 000000000..a51cc112b --- /dev/null +++ b/res/drawable-xxhdpi/apps_customize_bg.png diff --git a/res/drawable-xxhdpi/bg_cling1.png b/res/drawable-xxhdpi/bg_cling1.png Binary files differdeleted file mode 100644 index 077785600..000000000 --- a/res/drawable-xxhdpi/bg_cling1.png +++ /dev/null diff --git a/res/drawable-xxhdpi/bg_cling2.png b/res/drawable-xxhdpi/bg_cling2.png Binary files differdeleted file mode 100644 index 1797a1b6c..000000000 --- a/res/drawable-xxhdpi/bg_cling2.png +++ /dev/null diff --git a/res/drawable-xxhdpi/bg_cling3.png b/res/drawable-xxhdpi/bg_cling3.png Binary files differdeleted file mode 100644 index a87be630e..000000000 --- a/res/drawable-xxhdpi/bg_cling3.png +++ /dev/null diff --git a/res/drawable-xxhdpi/bg_cling4.png b/res/drawable-xxhdpi/bg_cling4.png Binary files differdeleted file mode 100644 index cabe919d5..000000000 --- a/res/drawable-xxhdpi/bg_cling4.png +++ /dev/null diff --git a/res/drawable-xxhdpi/bg_cling_home.png b/res/drawable-xxhdpi/bg_cling_home.png Binary files differdeleted file mode 100644 index 1ae93e7fe..000000000 --- a/res/drawable-xxhdpi/bg_cling_home.png +++ /dev/null diff --git a/res/drawable-xxhdpi/bg_cling_nakasi3.png b/res/drawable-xxhdpi/bg_cling_nakasi3.png Binary files differdeleted file mode 100644 index f47236cac..000000000 --- a/res/drawable-xxhdpi/bg_cling_nakasi3.png +++ /dev/null diff --git a/res/drawable-xxhdpi/cling.9.png b/res/drawable-xxhdpi/cling.9.png Binary files differdeleted file mode 100644 index 7beae03bf..000000000 --- a/res/drawable-xxhdpi/cling.9.png +++ /dev/null diff --git a/res/drawable-xxhdpi/cling_arrow_down.png b/res/drawable-xxhdpi/cling_arrow_down.png Binary files differdeleted file mode 100644 index 48c4f06fa..000000000 --- a/res/drawable-xxhdpi/cling_arrow_down.png +++ /dev/null diff --git a/res/drawable-xxhdpi/cling_arrow_left.png b/res/drawable-xxhdpi/cling_arrow_left.png Binary files differdeleted file mode 100644 index 8760d05da..000000000 --- a/res/drawable-xxhdpi/cling_arrow_left.png +++ /dev/null diff --git a/res/drawable-xxhdpi/cling_arrow_right.png b/res/drawable-xxhdpi/cling_arrow_right.png Binary files differdeleted file mode 100644 index 356ba178c..000000000 --- a/res/drawable-xxhdpi/cling_arrow_right.png +++ /dev/null diff --git a/res/drawable-xxhdpi/cling_arrow_up.png b/res/drawable-xxhdpi/cling_arrow_up.png Binary files differdeleted file mode 100644 index 4cb805f45..000000000 --- a/res/drawable-xxhdpi/cling_arrow_up.png +++ /dev/null diff --git a/res/drawable-xxhdpi/cling_bg.9.png b/res/drawable-xxhdpi/cling_bg.9.png Binary files differnew file mode 100644 index 000000000..dc9f69ae9 --- /dev/null +++ b/res/drawable-xxhdpi/cling_bg.9.png diff --git a/res/drawable-xxhdpi/cling_button.9.png b/res/drawable-xxhdpi/cling_button.9.png Binary files differdeleted file mode 100644 index e41287613..000000000 --- a/res/drawable-xxhdpi/cling_button.9.png +++ /dev/null diff --git a/res/drawable-xxhdpi/cling_button_pressed.9.png b/res/drawable-xxhdpi/cling_button_pressed.9.png Binary files differdeleted file mode 100644 index 55e89da08..000000000 --- a/res/drawable-xxhdpi/cling_button_pressed.9.png +++ /dev/null diff --git a/res/drawable-xxhdpi/focused_bg.9.png b/res/drawable-xxhdpi/focused_bg.9.png Binary files differdeleted file mode 100644 index 84d3062f1..000000000 --- a/res/drawable-xxhdpi/focused_bg.9.png +++ /dev/null diff --git a/res/drawable-xxhdpi/ic_allapps.png b/res/drawable-xxhdpi/ic_allapps.png Binary files differindex 624e0ef44..5dbfe4c5c 100644 --- a/res/drawable-xxhdpi/ic_allapps.png +++ b/res/drawable-xxhdpi/ic_allapps.png diff --git a/res/drawable-xxhdpi/ic_allapps_pressed.png b/res/drawable-xxhdpi/ic_allapps_pressed.png Binary files differindex 77b45aefb..e76172381 100644 --- a/res/drawable-xxhdpi/ic_allapps_pressed.png +++ b/res/drawable-xxhdpi/ic_allapps_pressed.png diff --git a/res/drawable-xxhdpi/ic_pageindicator_add.png b/res/drawable-xxhdpi/ic_pageindicator_add.png Binary files differindex fd8a662e1..c28895229 100644 --- a/res/drawable-xxhdpi/ic_pageindicator_add.png +++ b/res/drawable-xxhdpi/ic_pageindicator_add.png diff --git a/res/drawable-xxhdpi/ic_pageindicator_current.png b/res/drawable-xxhdpi/ic_pageindicator_current.png Binary files differindex 08615f371..b74e92ea7 100644 --- a/res/drawable-xxhdpi/ic_pageindicator_current.png +++ b/res/drawable-xxhdpi/ic_pageindicator_current.png diff --git a/res/drawable-xxhdpi/ic_pageindicator_default.png b/res/drawable-xxhdpi/ic_pageindicator_default.png Binary files differindex 9d4fbf820..e362ece71 100644 --- a/res/drawable-xxhdpi/ic_pageindicator_default.png +++ b/res/drawable-xxhdpi/ic_pageindicator_default.png diff --git a/res/drawable-xxhdpi/ic_setting.png b/res/drawable-xxhdpi/ic_setting.png Binary files differindex b3729d315..01bdcd544 100644 --- a/res/drawable-xxhdpi/ic_setting.png +++ b/res/drawable-xxhdpi/ic_setting.png diff --git a/res/drawable-xxhdpi/ic_setting_pressed.png b/res/drawable-xxhdpi/ic_setting_pressed.png Binary files differindex 5c9c1be44..d0cad5e0e 100644 --- a/res/drawable-xxhdpi/ic_setting_pressed.png +++ b/res/drawable-xxhdpi/ic_setting_pressed.png diff --git a/res/drawable-xxhdpi/ic_wallpaper.png b/res/drawable-xxhdpi/ic_wallpaper.png Binary files differindex c71844410..490c45a87 100644 --- a/res/drawable-xxhdpi/ic_wallpaper.png +++ b/res/drawable-xxhdpi/ic_wallpaper.png diff --git a/res/drawable-xxhdpi/ic_wallpaper_pressed.png b/res/drawable-xxhdpi/ic_wallpaper_pressed.png Binary files differindex 03324aa6c..e5d200be1 100644 --- a/res/drawable-xxhdpi/ic_wallpaper_pressed.png +++ b/res/drawable-xxhdpi/ic_wallpaper_pressed.png diff --git a/res/drawable-xxhdpi/ic_widget.png b/res/drawable-xxhdpi/ic_widget.png Binary files differindex fddfecaa3..d4b8324b1 100644 --- a/res/drawable-xxhdpi/ic_widget.png +++ b/res/drawable-xxhdpi/ic_widget.png diff --git a/res/drawable-xxhdpi/ic_widget_pressed.png b/res/drawable-xxhdpi/ic_widget_pressed.png Binary files differindex 3d3670ed4..b8dd35dc6 100644 --- a/res/drawable-xxhdpi/ic_widget_pressed.png +++ b/res/drawable-xxhdpi/ic_widget_pressed.png diff --git a/res/drawable-xxhdpi/page_hover_left.9.png b/res/drawable-xxhdpi/page_hover_left.9.png Binary files differnew file mode 100644 index 000000000..63869dd3e --- /dev/null +++ b/res/drawable-xxhdpi/page_hover_left.9.png diff --git a/res/drawable-xxhdpi/page_hover_left_active.9.png b/res/drawable-xxhdpi/page_hover_left_active.9.png Binary files differnew file mode 100644 index 000000000..9a418ce1e --- /dev/null +++ b/res/drawable-xxhdpi/page_hover_left_active.9.png diff --git a/res/drawable-xxhdpi/page_hover_left_holo.9.png b/res/drawable-xxhdpi/page_hover_left_holo.9.png Binary files differdeleted file mode 100644 index 626aafb55..000000000 --- a/res/drawable-xxhdpi/page_hover_left_holo.9.png +++ /dev/null diff --git a/res/drawable-xxhdpi/page_hover_right.9.png b/res/drawable-xxhdpi/page_hover_right.9.png Binary files differnew file mode 100644 index 000000000..c6fd39885 --- /dev/null +++ b/res/drawable-xxhdpi/page_hover_right.9.png diff --git a/res/drawable-xxhdpi/page_hover_right_active.9.png b/res/drawable-xxhdpi/page_hover_right_active.9.png Binary files differnew file mode 100644 index 000000000..7aef3733c --- /dev/null +++ b/res/drawable-xxhdpi/page_hover_right_active.9.png diff --git a/res/drawable-xxhdpi/page_hover_right_holo.9.png b/res/drawable-xxhdpi/page_hover_right_holo.9.png Binary files differdeleted file mode 100644 index 66257dc8e..000000000 --- a/res/drawable-xxhdpi/page_hover_right_holo.9.png +++ /dev/null diff --git a/res/drawable-xxhdpi/quantum_panel.9.png b/res/drawable-xxhdpi/quantum_panel.9.png Binary files differnew file mode 100644 index 000000000..d7ba87416 --- /dev/null +++ b/res/drawable-xxhdpi/quantum_panel.9.png diff --git a/res/drawable-xxhdpi/quantum_panel_dark.9.png b/res/drawable-xxhdpi/quantum_panel_dark.9.png Binary files differnew file mode 100644 index 000000000..17ba0f116 --- /dev/null +++ b/res/drawable-xxhdpi/quantum_panel_dark.9.png diff --git a/res/drawable-xxhdpi/screenpanel.9.png b/res/drawable-xxhdpi/screenpanel.9.png Binary files differindex c44f3b898..2d1395479 100644 --- a/res/drawable-xxhdpi/screenpanel.9.png +++ b/res/drawable-xxhdpi/screenpanel.9.png diff --git a/res/drawable-xxhdpi/screenpanel_hover.9.png b/res/drawable-xxhdpi/screenpanel_hover.9.png Binary files differindex e8b36d8f1..369fc44e1 100644 --- a/res/drawable-xxhdpi/screenpanel_hover.9.png +++ b/res/drawable-xxhdpi/screenpanel_hover.9.png diff --git a/res/drawable-xxhdpi/virtual_preload.9.png b/res/drawable-xxhdpi/virtual_preload.9.png Binary files differnew file mode 100644 index 000000000..93e3b3362 --- /dev/null +++ b/res/drawable-xxhdpi/virtual_preload.9.png diff --git a/res/drawable-xxhdpi/virtual_preload_folder.9.png b/res/drawable-xxhdpi/virtual_preload_folder.9.png Binary files differnew file mode 100644 index 000000000..fae19b3f9 --- /dev/null +++ b/res/drawable-xxhdpi/virtual_preload_folder.9.png diff --git a/res/drawable-xxhdpi/widget_container_holo.9.png b/res/drawable-xxhdpi/widget_container_holo.9.png Binary files differdeleted file mode 100644 index 8f79920c4..000000000 --- a/res/drawable-xxhdpi/widget_container_holo.9.png +++ /dev/null diff --git a/res/drawable/bg_migration_cling.xml b/res/drawable/bg_migration_cling.xml new file mode 100644 index 000000000..bfff5a41a --- /dev/null +++ b/res/drawable/bg_migration_cling.xml @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="utf-8"?> +<shape xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="oval" > + + <gradient + android:endColor="#00ffeb3a" + android:gradientRadius="50%p" + android:startColor="#80ffeb3a" + android:type="radial" /> + +</shape>
\ No newline at end of file diff --git a/res/drawable/cling_arrow_start.xml b/res/drawable/cling_arrow_start.xml deleted file mode 100644 index ebe91830d..000000000 --- a/res/drawable/cling_arrow_start.xml +++ /dev/null @@ -1,19 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2013 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. ---> -<bitmap xmlns:android="http://schemas.android.com/apk/res/android" - android:src="@drawable/cling_arrow_left" - android:autoMirrored="true"> -</bitmap> diff --git a/res/drawable/cling_button_bg.xml b/res/drawable/cling_button_bg.xml deleted file mode 100644 index 7bf6ce79f..000000000 --- a/res/drawable/cling_button_bg.xml +++ /dev/null @@ -1,20 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2011 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. ---> - -<selector xmlns:android="http://schemas.android.com/apk/res/android"> - <item android:state_pressed="true" android:drawable="@drawable/cling_button_pressed" /> - <item android:drawable="@drawable/cling_button" /> -</selector> diff --git a/res/drawable/focusable_view_bg.xml b/res/drawable/focusable_view_bg.xml index 66661e28b..e156513ef 100644 --- a/res/drawable/focusable_view_bg.xml +++ b/res/drawable/focusable_view_bg.xml @@ -1,5 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2011 The Android Open Source Project +<!-- + Copyright (C) 2011 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. @@ -15,5 +16,11 @@ --> <selector xmlns:android="http://schemas.android.com/apk/res/android"> - <item android:state_focused="true" android:drawable="@drawable/focused_bg" /> -</selector> + + <item android:state_focused="true"> + <shape android:shape="rectangle"> + <solid android:color="@color/focused_background" /> + </shape> + </item> + +</selector>
\ No newline at end of file diff --git a/res/interpolator/decelerate_quart.xml b/res/interpolator/decelerate_quart.xml new file mode 100644 index 000000000..5dc5d3857 --- /dev/null +++ b/res/interpolator/decelerate_quart.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** Copyright 2014, 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. +*/ +--> + +<decelerateInterpolator xmlns:android="http://schemas.android.com/apk/res/android" + android:factor="2" /> diff --git a/res/interpolator/decelerate_quint.xml b/res/interpolator/decelerate_quint.xml new file mode 100644 index 000000000..fa89a648e --- /dev/null +++ b/res/interpolator/decelerate_quint.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** Copyright 2014, 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. +*/ +--> + +<decelerateInterpolator xmlns:android="http://schemas.android.com/apk/res/android" + android:factor="2.5" /> diff --git a/res/layout-land/first_run_cling.xml b/res/layout-land/first_run_cling.xml deleted file mode 100644 index 9baee64b7..000000000 --- a/res/layout-land/first_run_cling.xml +++ /dev/null @@ -1,97 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2011 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. ---> -<com.android.launcher3.Cling - xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:launcher="http://schemas.android.com/apk/res-auto/com.android.launcher3" - android:layout_width="match_parent" - android:layout_height="match_parent" - launcher:drawIdentifier="first_run_portrait"> - <FrameLayout - android:id="@+id/content" - android:layout_width="match_parent" - android:layout_height="match_parent"> - <LinearLayout - android:id="@+id/bubble_content" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_gravity="center" - android:layout_marginLeft="100dp" - android:layout_marginRight="100dp" - android:orientation="vertical"> - <TextView - style="@style/ClingAltTitleText" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_gravity="center_horizontal" - android:layout_marginBottom="10dp" - android:text="@string/first_run_cling_title" - android:textColor="#FFFFFFFF" - android:textSize="30sp" - android:gravity="center" /> - <TextView - style="@style/ClingAltTitleText" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_gravity="center_horizontal" - android:text="@string/first_run_cling_description" - android:textColor="#80000000" - android:textSize="16sp" - android:gravity="center" /> - </LinearLayout> - <TextView - style="@style/ClingHintText" - android:id="@+id/search_bar_hint" - android:layout_width="160dp" - android:layout_height="wrap_content" - android:layout_gravity="top|end" - android:layout_marginEnd="10dp" - android:layout_marginTop="65dp" - android:visibility="gone" - android:drawableTop="@drawable/cling_arrow_up" - android:drawablePadding="5dp" - android:text="@string/first_run_cling_search_bar_hint" /> - <TextView - style="@style/ClingHintText" - android:id="@+id/custom_content_hint" - android:layout_width="160dp" - android:layout_height="wrap_content" - android:layout_gravity="top" - android:layout_marginStart="10dp" - android:layout_marginTop="100dp" - android:visibility="gone" - android:drawableStart="@drawable/cling_arrow_left" - android:drawablePadding="10dp" - android:text="@string/first_run_cling_custom_content_hint" /> - <TextView - style="@style/ClingHintText" - android:layout_width="160dp" - android:layout_height="wrap_content" - android:layout_gravity="bottom|end" - android:layout_marginEnd="10dp" - android:layout_marginBottom="85dp" - android:drawableEnd="@drawable/cling_arrow_right" - android:drawablePadding="5dp" - android:text="@string/first_run_cling_create_screens_hint" /> - </FrameLayout> - <Button - style="@style/ClingButton" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginBottom="15dp" - android:layout_marginEnd="20dp" - android:layout_gravity="bottom|end" - android:onClick="dismissFirstRunCling" /> -</com.android.launcher3.Cling> diff --git a/res/layout-land/folder_cling.xml b/res/layout-land/folder_cling.xml deleted file mode 100644 index 5dd372973..000000000 --- a/res/layout-land/folder_cling.xml +++ /dev/null @@ -1,65 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2011 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. ---> -<com.android.launcher3.Cling - xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:launcher="http://schemas.android.com/apk/res-auto/com.android.launcher3" - launcher:drawIdentifier="folder_landscape"> - <FrameLayout - android:layout_width="match_parent" - android:layout_height="match_parent" - android:layout_marginStart="15dp" - android:layout_marginEnd="15dp" - android:layout_marginTop="10dp" - android:layout_marginBottom="10dp"> - <LinearLayout - android:id="@+id/folder_bubble" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:orientation="vertical"> - <LinearLayout - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:paddingLeft="20dp" - android:paddingRight="20dp" - android:paddingTop="20dp" - android:paddingBottom="20dp" - android:orientation="vertical" - android:background="@drawable/cling"> - <TextView - style="@style/ClingTitleText" - android:id="@+id/folder_cling_title" - android:text="@string/folder_cling_title" /> - <TextView - style="@style/ClingText" - android:id="@+id/folder_cling_create_folder" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:text="@string/folder_cling_create_folder" /> - </LinearLayout> - <ImageView - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:src="@drawable/cling_arrow_down" /> - </LinearLayout> - </FrameLayout> - <Button - style="@style/ClingButton" - android:id="@+id/cling_dismiss" - android:layout_marginBottom="15dp" - android:layout_marginEnd="20dp" - android:layout_gravity="bottom|right" - android:onClick="dismissFolderCling" /> -</com.android.launcher3.Cling> diff --git a/res/layout-land/launcher.xml b/res/layout-land/launcher.xml index 779160925..8cd867366 100644 --- a/res/layout-land/launcher.xml +++ b/res/layout-land/launcher.xml @@ -30,6 +30,11 @@ android:layout_height="match_parent" android:fitsSystemWindows="true"> + <com.android.launcher3.FocusIndicatorView + android:id="@+id/focus_indicator" + android:layout_width="52dp" + android:layout_height="52dp" /> + <!-- The workspace contains 5 screens of cells --> <com.android.launcher3.Workspace android:id="@+id/workspace" @@ -52,40 +57,6 @@ android:id="@+id/overview_panel" android:visibility="gone" /> - <!-- The Workspace cling must appear under the AppsCustomizePagedView below to ensure - that it is still visible during the transition to AllApps and doesn't overlay on - top of that view. --> - <com.android.launcher3.ScrimView - android:id="@+id/cling_scrim" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:visibility="gone" /> - <include layout="@layout/first_run_cling" - android:id="@+id/first_run_cling" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:visibility="gone" /> - <include layout="@layout/migration_cling" - android:id="@+id/migration_cling" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:visibility="gone" /> - <include layout="@layout/migration_workspace_cling" - android:id="@+id/migration_workspace_cling" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:visibility="gone" /> - <include layout="@layout/workspace_cling" - android:id="@+id/workspace_cling" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:visibility="gone" /> - <include layout="@layout/folder_cling" - android:id="@+id/folder_cling" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:visibility="gone" /> - <include layout="@layout/apps_customize_pane" android:id="@+id/apps_customize_pane" android:layout_width="match_parent" diff --git a/res/layout-land/longpress_cling.xml b/res/layout-land/longpress_cling.xml new file mode 100644 index 000000000..93bbc077a --- /dev/null +++ b/res/layout-land/longpress_cling.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:launcher="http://schemas.android.com/apk/res-auto/com.android.launcher3" + android:id="@+id/longpress_cling" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:background="@color/cling_scrim_background" + android:orientation="vertical" > + + <Space + android:layout_width="match_parent" + android:layout_height="0dp" + android:layout_weight="1" /> + + <FrameLayout + android:id="@+id/cling_content" + android:layout_width="360dp" + android:layout_height="wrap_content" + android:layout_gravity="center_horizontal" + android:background="@drawable/cling_bg" /> + + <Space + android:layout_width="match_parent" + android:layout_height="0dp" + android:layout_weight="2" /> + +</LinearLayout>
\ No newline at end of file diff --git a/res/layout-land/migration_cling.xml b/res/layout-land/migration_cling.xml index 343f43f1f..307cba8a8 100644 --- a/res/layout-land/migration_cling.xml +++ b/res/layout-land/migration_cling.xml @@ -1,5 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2011 The Android Open Source Project +<!-- + Copyright (C) 2011 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. @@ -13,88 +14,90 @@ See the License for the specific language governing permissions and limitations under the License. --> -<com.android.launcher3.Cling - xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:launcher="http://schemas.android.com/apk/res-auto/com.android.launcher3" +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/migration_cling" android:layout_width="match_parent" android:layout_height="match_parent" - launcher:drawIdentifier="migration_landscape"> + android:background="#FF009688" + android:baselineAligned="false" + android:gravity="center_vertical" > + <FrameLayout - android:id="@+id/content" - android:layout_width="match_parent" + android:layout_width="0dp" android:layout_height="match_parent" - android:orientation="vertical"> + android:layout_weight="1" > - <LinearLayout - android:layout_width="match_parent" + <ImageView + android:layout_width="@dimen/cling_migration_bg_size" + android:layout_height="@dimen/cling_migration_bg_size" + android:layout_gravity="center" + android:background="@drawable/bg_migration_cling" /> + + <ImageView + android:layout_width="@dimen/cling_migration_logo_width" + android:layout_height="@dimen/cling_migration_logo_height" + android:layout_gravity="center" + android:src="@drawable/ic_migration" /> + </FrameLayout> + + <LinearLayout + android:layout_width="@dimen/cling_migration_content_width" + android:layout_height="wrap_content" + android:layout_marginEnd="@dimen/cling_migration_content_margin" + android:orientation="vertical" + android:paddingLeft="24dp" + android:paddingRight="24dp" > + + <TextView + android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_gravity="top" - android:orientation="vertical"> - <TextView - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_gravity="top" - android:gravity="center" - android:text="@string/first_run_cling_title" - android:textSize="42dp" - android:textColor="#FFffffff" /> - <ImageView - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginTop="10dp" - android:layout_marginBottom="0dp" - android:layout_gravity="center_horizontal" - android:src="@drawable/on_boarding_welcome" /> + android:paddingBottom="8dp" + android:text="@string/first_run_cling_title" + android:textColor="#E1000000" + android:textSize="34sp" /> - <ImageView - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center_horizontal" - android:src="@drawable/cling_arrow_up" /> - <LinearLayout - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginLeft="25dp" - android:layout_marginRight="25dp" - android:paddingLeft="25dp" - android:paddingRight="25dp" - android:paddingTop="20dp" - android:paddingBottom="20dp" - android:orientation="vertical" - android:background="@drawable/cling"> - <TextView - style="@style/ClingTitleText" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:text="@string/migration_cling_title" /> - <TextView - style="@style/ClingText" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:text="@string/migration_cling_description" /> - </LinearLayout> - </LinearLayout> + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:fontFamily="sans-serif-medium" + android:text="@string/migration_cling_title" + android:textColor="#E1000000" + android:textSize="20sp" /> + + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:paddingBottom="24dp" + android:text="@string/migration_cling_description" + android:textColor="#99000000" + android:textSize="16sp" /> <LinearLayout android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_gravity="bottom" - android:layout_marginLeft="25dp" - android:layout_marginRight="25dp" - android:layout_marginBottom="25dp" - android:orientation="vertical"> + android:layout_height="wrap_content" > + <Button - style="@style/ClingButton" - android:layout_width="match_parent" + android:id="@+id/cling_dismiss_migration_copy_apps" + style="?android:attr/buttonBarButtonStyle" + android:layout_width="0dp" android:layout_height="wrap_content" + android:layout_weight="1" + android:fontFamily="sans-serif-medium" android:text="@string/migration_cling_copy_apps" - android:onClick="dismissMigrationClingCopyApps" /> + android:textColor="#FFFFFFFF" + android:textSize="14sp" /> + <Button - style="@style/ClingButton" - android:layout_width="match_parent" + android:id="@+id/cling_dismiss_migration_use_default" + style="?android:attr/buttonBarButtonStyle" + android:layout_width="0dp" android:layout_height="wrap_content" + android:layout_weight="1" + android:fontFamily="sans-serif-medium" android:text="@string/migration_cling_use_default" - android:onClick="dismissMigrationClingUseDefault" /> + android:textColor="#deFFFFFF" + android:textSize="14sp" /> </LinearLayout> - </FrameLayout> -</com.android.launcher3.Cling> + </LinearLayout> + +</LinearLayout>
\ No newline at end of file diff --git a/res/layout-land/migration_workspace_cling.xml b/res/layout-land/migration_workspace_cling.xml deleted file mode 100644 index 1148be45f..000000000 --- a/res/layout-land/migration_workspace_cling.xml +++ /dev/null @@ -1,70 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2011 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. ---> -<com.android.launcher3.Cling - xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:launcher="http://schemas.android.com/apk/res-auto/com.android.launcher3" - android:layout_width="match_parent" - android:layout_height="match_parent" - launcher:drawIdentifier="migration_workspace_landscape"> - <LinearLayout - android:id="@+id/content" - android:layout_width="400dp" - android:layout_height="wrap_content" - android:layout_gravity="end|center_vertical" - android:paddingEnd="60dp" - android:paddingRight="60dp" - android:orientation="vertical"> - <LinearLayout - android:id="@+id/migration_workspace_cling_bubble" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:orientation="horizontal"> - <LinearLayout - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginRight="4dp" - android:paddingLeft="20dp" - android:paddingRight="20dp" - android:paddingTop="20dp" - android:paddingBottom="20dp" - android:orientation="vertical" - android:background="@drawable/cling"> - <TextView - style="@style/ClingTitleText" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:text="@string/workspace_cling_title" /> - <TextView - style="@style/ClingText" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:text="@string/workspace_cling_move_item" /> - </LinearLayout> - <ImageView - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center_vertical" - android:src="@drawable/cling_arrow_end" /> - </LinearLayout> - <Button - style="@style/ClingButton" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginTop="5dp" - android:layout_gravity="right" - android:onClick="dismissMigrationWorkspaceCling" /> - </LinearLayout> -</com.android.launcher3.Cling> diff --git a/res/layout-land/workspace_cling.xml b/res/layout-land/workspace_cling.xml deleted file mode 100644 index d3b07d74d..000000000 --- a/res/layout-land/workspace_cling.xml +++ /dev/null @@ -1,108 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2011 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. ---> -<com.android.launcher3.Cling - xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:launcher="http://schemas.android.com/apk/res-auto/com.android.launcher3" - android:layout_width="match_parent" - android:layout_height="match_parent" - launcher:drawIdentifier="workspace_landscape"> - <FrameLayout - android:id="@+id/content" - android:layout_width="match_parent" - android:layout_height="match_parent"> - <LinearLayout - android:id="@+id/workspace_cling_bubble" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_gravity="top" - android:layout_marginStart="25dp" - android:layout_marginEnd="25dp" - android:layout_marginTop="30dp" - android:orientation="vertical"> - <LinearLayout - android:paddingLeft="20dp" - android:paddingRight="20dp" - android:paddingTop="20dp" - android:paddingBottom="20dp" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:orientation="vertical" - android:background="@drawable/cling"> - <TextView - style="@style/ClingTitleText" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:text="@string/workspace_cling_title" /> - <TextView - style="@style/ClingText" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:text="@string/workspace_cling_move_item" /> - </LinearLayout> - <ImageView - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center_horizontal" - android:src="@drawable/cling_arrow_down" /> - </LinearLayout> - - <LinearLayout - android:id="@+id/focused_hotseat_app_bubble" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="bottom|left" - android:layout_marginLeft="25dp" - android:layout_marginBottom="90dp" - android:orientation="vertical" - android:visibility="gone"> - <LinearLayout - android:paddingLeft="20dp" - android:paddingRight="20dp" - android:paddingTop="20dp" - android:paddingBottom="20dp" - android:layout_width="240dp" - android:layout_height="wrap_content" - android:orientation="vertical" - android:background="@drawable/cling"> - <TextView - android:id="@+id/focused_hotseat_app_title" - style="@style/ClingTitleText" - android:layout_width="wrap_content" - android:layout_height="wrap_content" /> - <TextView - android:id="@+id/focused_hotseat_app_description" - style="@style/ClingText" - android:layout_width="match_parent" - android:layout_height="wrap_content" /> - </LinearLayout> - <ImageView - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="left" - android:layout_marginLeft="78dp" - android:src="@drawable/cling_arrow_down" /> - </LinearLayout> - </FrameLayout> - - <Button - style="@style/ClingButton" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginBottom="15dp" - android:layout_marginRight="20dp" - android:layout_gravity="bottom|right" - android:onClick="dismissWorkspaceCling" /> -</com.android.launcher3.Cling> diff --git a/res/layout-port/first_run_cling.xml b/res/layout-port/first_run_cling.xml deleted file mode 100644 index ac3939cfd..000000000 --- a/res/layout-port/first_run_cling.xml +++ /dev/null @@ -1,100 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2011 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. ---> -<com.android.launcher3.Cling - xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:launcher="http://schemas.android.com/apk/res-auto/com.android.launcher3" - android:layout_width="match_parent" - android:layout_height="match_parent" - launcher:drawIdentifier="first_run_portrait"> - <FrameLayout - android:id="@+id/content" - android:layout_width="match_parent" - android:layout_height="match_parent"> - <LinearLayout - android:id="@+id/bubble_content" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_gravity="center" - android:layout_marginLeft="100dp" - android:layout_marginRight="100dp" - android:orientation="vertical"> - <TextView - style="@style/ClingAltTitleText" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_gravity="center_horizontal" - android:layout_marginBottom="10dp" - android:text="@string/first_run_cling_title" - android:textColor="#FFFFFFFF" - android:gravity="center" /> - <TextView - style="@style/ClingAltText" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_gravity="center_horizontal" - android:text="@string/first_run_cling_description" - android:textColor="#80000000" - android:gravity="center" /> - </LinearLayout> - <TextView - style="@style/ClingHintText" - android:id="@+id/search_bar_hint" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="top|end" - android:layout_marginEnd="10dp" - android:layout_marginTop="65dp" - android:gravity="center_horizontal" - android:maxWidth="160dp" - android:visibility="gone" - android:drawableTop="@drawable/cling_arrow_up" - android:drawablePadding="5dp" - android:text="@string/first_run_cling_search_bar_hint" /> - <TextView - style="@style/ClingHintText" - android:id="@+id/custom_content_hint" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="top|start" - android:layout_marginStart="10dp" - android:layout_marginEnd="10dp" - android:layout_marginTop="100dp" - android:maxWidth="160dp" - android:visibility="gone" - android:drawableStart="@drawable/cling_arrow_start" - android:drawablePadding="10dp" - android:text="@string/first_run_cling_custom_content_hint" /> - <TextView - style="@style/ClingHintText" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="bottom|end" - android:layout_marginEnd="10dp" - android:layout_marginBottom="85dp" - android:maxWidth="180dp" - android:drawableEnd="@drawable/cling_arrow_end" - android:drawablePadding="5dp" - android:text="@string/first_run_cling_create_screens_hint" /> - </FrameLayout> - <Button - style="@style/ClingButton" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginBottom="15dp" - android:layout_marginEnd="20dp" - android:layout_gravity="bottom|end" - android:onClick="dismissFirstRunCling" /> -</com.android.launcher3.Cling> diff --git a/res/layout-port/folder_cling.xml b/res/layout-port/folder_cling.xml deleted file mode 100644 index 1a1b11fce..000000000 --- a/res/layout-port/folder_cling.xml +++ /dev/null @@ -1,65 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2011 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. ---> -<com.android.launcher3.Cling - xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:launcher="http://schemas.android.com/apk/res-auto/com.android.launcher3" - launcher:drawIdentifier="folder_portrait"> - <FrameLayout - android:layout_width="match_parent" - android:layout_height="match_parent" - android:layout_marginStart="15dp" - android:layout_marginEnd="15dp" - android:layout_marginTop="10dp" - android:layout_marginBottom="10dp"> - <LinearLayout - android:id="@+id/folder_bubble" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:orientation="vertical"> - <LinearLayout - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:paddingLeft="20dp" - android:paddingRight="20dp" - android:paddingTop="20dp" - android:paddingBottom="20dp" - android:orientation="vertical" - android:background="@drawable/cling"> - <TextView - style="@style/ClingTitleText" - android:id="@+id/folder_cling_title" - android:text="@string/folder_cling_title" /> - <TextView - style="@style/ClingText" - android:id="@+id/folder_cling_create_folder" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:text="@string/folder_cling_create_folder" /> - </LinearLayout> - <ImageView - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:src="@drawable/cling_arrow_down" /> - </LinearLayout> - </FrameLayout> - <Button - style="@style/ClingButton" - android:id="@+id/cling_dismiss" - android:layout_marginBottom="15dp" - android:layout_marginEnd="20dp" - android:layout_gravity="bottom|right" - android:onClick="dismissFolderCling" /> -</com.android.launcher3.Cling> diff --git a/res/layout-port/launcher.xml b/res/layout-port/launcher.xml index 574b73e46..9e98d4257 100644 --- a/res/layout-port/launcher.xml +++ b/res/layout-port/launcher.xml @@ -29,6 +29,11 @@ android:layout_width="match_parent" android:layout_height="match_parent"> + <com.android.launcher3.FocusIndicatorView + android:id="@+id/focus_indicator" + android:layout_width="52dp" + android:layout_height="52dp" /> + <!-- The workspace contains 5 screens of cells --> <com.android.launcher3.Workspace android:id="@+id/workspace" @@ -60,40 +65,6 @@ android:id="@+id/search_drop_target_bar" layout="@layout/search_drop_target_bar" /> - <!-- The Workspace cling must appear under the AppsCustomizePagedView below to ensure - that it is still visible during the transition to AllApps and doesn't overlay on - top of that view. --> - <com.android.launcher3.ScrimView - android:id="@+id/cling_scrim" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:visibility="gone" /> - <include layout="@layout/first_run_cling" - android:id="@+id/first_run_cling" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:visibility="gone" /> - <include layout="@layout/migration_cling" - android:id="@+id/migration_cling" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:visibility="gone" /> - <include layout="@layout/migration_workspace_cling" - android:id="@+id/migration_workspace_cling" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:visibility="gone" /> - <include layout="@layout/workspace_cling" - android:id="@+id/workspace_cling" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:visibility="gone" /> - <include layout="@layout/folder_cling" - android:id="@+id/folder_cling" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:visibility="gone" /> - <!-- This is the search bar voice button proxy view. It allows us to have a larger touch target than the microphone constrained by the search bar bounds. --> <com.android.launcher3.DrawableStateProxyView diff --git a/res/layout-port/longpress_cling.xml b/res/layout-port/longpress_cling.xml new file mode 100644 index 000000000..8e35f5c1a --- /dev/null +++ b/res/layout-port/longpress_cling.xml @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="utf-8"?> +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:launcher="http://schemas.android.com/apk/res-auto/com.android.launcher3" + android:id="@+id/longpress_cling" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:background="@color/cling_scrim_background" > + + <FrameLayout + android:id="@+id/cling_content" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_gravity="top" + android:background="@drawable/cling_bg" + android:tag="crop_bg_top_and_sides" /> + +</FrameLayout>
\ No newline at end of file diff --git a/res/layout-port/migration_cling.xml b/res/layout-port/migration_cling.xml index 1bffe6c82..dde8dbcdb 100644 --- a/res/layout-port/migration_cling.xml +++ b/res/layout-port/migration_cling.xml @@ -1,5 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2011 The Android Open Source Project +<!-- + Copyright (C) 2011 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. @@ -13,88 +14,93 @@ See the License for the specific language governing permissions and limitations under the License. --> -<com.android.launcher3.Cling - xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:launcher="http://schemas.android.com/apk/res-auto/com.android.launcher3" +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/migration_cling" android:layout_width="match_parent" android:layout_height="match_parent" - launcher:drawIdentifier="migration_portrait"> - <FrameLayout - android:id="@+id/content" + android:background="#FF009688" > + + <RelativeLayout android:layout_width="match_parent" - android:layout_height="match_parent" - android:orientation="vertical"> + android:layout_height="wrap_content" + android:layout_gravity="center_vertical" > + + <ImageView + android:layout_width="@dimen/cling_migration_bg_size" + android:layout_height="@dimen/cling_migration_bg_size" + android:layout_below="@+id/ic_cling_migration" + android:layout_centerHorizontal="true" + android:layout_marginTop="@dimen/cling_migration_bg_shift" + android:src="@drawable/bg_migration_cling" /> + + <ImageView + android:id="@+id/ic_cling_migration" + android:layout_width="@dimen/cling_migration_logo_width" + android:layout_height="@dimen/cling_migration_logo_height" + android:layout_alignParentTop="true" + android:layout_centerHorizontal="true" + android:src="@drawable/ic_migration" /> <LinearLayout - android:layout_width="match_parent" + android:layout_width="@dimen/cling_migration_content_width" android:layout_height="wrap_content" - android:layout_gravity="top" - android:orientation="vertical"> + android:layout_below="@+id/ic_cling_migration" + android:layout_marginStart="@dimen/cling_migration_content_margin" + android:orientation="vertical" + android:paddingLeft="24dp" + android:paddingRight="24dp" > + <TextView - android:layout_width="match_parent" + android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_gravity="top" - android:gravity="center" + android:paddingBottom="8dp" android:text="@string/first_run_cling_title" - android:textSize="42dp" - android:textColor="#FFffffff" /> - <ImageView + android:textColor="#E1000000" + android:textSize="34sp" /> + + <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginTop="10dp" - android:layout_marginBottom="0dp" - android:layout_gravity="center_horizontal" - android:src="@drawable/on_boarding_welcome" /> + android:fontFamily="sans-serif-medium" + android:text="@string/migration_cling_title" + android:textColor="#E1000000" + android:textSize="20sp" /> - <ImageView + <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_gravity="center_horizontal" - android:src="@drawable/cling_arrow_up" /> + android:paddingBottom="24dp" + android:text="@string/migration_cling_description" + android:textColor="#99000000" + android:textSize="16sp" /> + <LinearLayout android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginLeft="25dp" - android:layout_marginRight="25dp" - android:paddingLeft="25dp" - android:paddingRight="25dp" - android:paddingTop="20dp" - android:paddingBottom="20dp" - android:orientation="vertical" - android:background="@drawable/cling"> - <TextView - style="@style/ClingTitleText" - android:layout_width="wrap_content" + android:layout_height="wrap_content" > + + <Button + android:id="@+id/cling_dismiss_migration_copy_apps" + style="?android:attr/buttonBarButtonStyle" + android:layout_width="0dp" android:layout_height="wrap_content" - android:text="@string/migration_cling_title" /> - <TextView - style="@style/ClingText" - android:layout_width="match_parent" + android:layout_weight="1" + android:fontFamily="sans-serif-medium" + android:text="@string/migration_cling_copy_apps" + android:textColor="#FFFFFFFF" + android:textSize="14sp" /> + + <Button + android:id="@+id/cling_dismiss_migration_use_default" + style="?android:attr/buttonBarButtonStyle" + android:layout_width="0dp" android:layout_height="wrap_content" - android:text="@string/migration_cling_description" /> + android:layout_weight="1" + android:fontFamily="sans-serif-medium" + android:text="@string/migration_cling_use_default" + android:textColor="#deFFFFFF" + android:textSize="14sp" /> </LinearLayout> </LinearLayout> + </RelativeLayout> - <LinearLayout - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_gravity="bottom" - android:layout_marginLeft="25dp" - android:layout_marginRight="25dp" - android:layout_marginBottom="25dp" - android:orientation="vertical"> - <Button - style="@style/ClingButton" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:text="@string/migration_cling_copy_apps" - android:onClick="dismissMigrationClingCopyApps" /> - <Button - style="@style/ClingButton" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:text="@string/migration_cling_use_default" - android:onClick="dismissMigrationClingUseDefault" /> - </LinearLayout> - </FrameLayout> -</com.android.launcher3.Cling> +</FrameLayout>
\ No newline at end of file diff --git a/res/layout-port/migration_workspace_cling.xml b/res/layout-port/migration_workspace_cling.xml deleted file mode 100644 index 576bb41f2..000000000 --- a/res/layout-port/migration_workspace_cling.xml +++ /dev/null @@ -1,70 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2011 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. ---> -<com.android.launcher3.Cling - xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:launcher="http://schemas.android.com/apk/res-auto/com.android.launcher3" - android:layout_width="match_parent" - android:layout_height="match_parent" - launcher:drawIdentifier="migration_workspace_portrait"> - <FrameLayout - android:id="@+id/content" - android:layout_width="match_parent" - android:layout_height="match_parent"> - <LinearLayout - android:id="@+id/migration_workspace_cling_bubble" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_gravity="bottom" - android:layout_marginStart="25dp" - android:layout_marginEnd="25dp" - android:orientation="vertical"> - <LinearLayout - android:paddingLeft="20dp" - android:paddingRight="20dp" - android:paddingTop="20dp" - android:paddingBottom="20dp" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:orientation="vertical" - android:background="@drawable/cling"> - <TextView - style="@style/ClingTitleText" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:text="@string/workspace_cling_title" /> - <TextView - style="@style/ClingText" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:text="@string/workspace_cling_move_item" /> - </LinearLayout> - <ImageView - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center_horizontal" - android:src="@drawable/cling_arrow_down" /> - </LinearLayout> - - <Button - style="@style/ClingButton" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginBottom="15dp" - android:layout_marginEnd="20dp" - android:layout_gravity="bottom|right" - android:onClick="dismissMigrationWorkspaceCling" /> - </FrameLayout> -</com.android.launcher3.Cling> diff --git a/res/layout-port/workspace_cling.xml b/res/layout-port/workspace_cling.xml deleted file mode 100644 index 624568668..000000000 --- a/res/layout-port/workspace_cling.xml +++ /dev/null @@ -1,108 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2011 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. ---> -<com.android.launcher3.Cling - xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:launcher="http://schemas.android.com/apk/res-auto/com.android.launcher3" - android:layout_width="match_parent" - android:layout_height="match_parent" - launcher:drawIdentifier="workspace_portrait"> - <FrameLayout - android:id="@+id/content" - android:layout_width="match_parent" - android:layout_height="match_parent"> - <LinearLayout - android:id="@+id/workspace_cling_bubble" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_gravity="top" - android:layout_marginStart="25dp" - android:layout_marginEnd="25dp" - android:layout_marginTop="30dp" - android:orientation="vertical"> - <LinearLayout - android:paddingLeft="20dp" - android:paddingRight="20dp" - android:paddingTop="20dp" - android:paddingBottom="20dp" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:orientation="vertical" - android:background="@drawable/cling"> - <TextView - style="@style/ClingTitleText" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:text="@string/workspace_cling_title" /> - <TextView - style="@style/ClingText" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:text="@string/workspace_cling_move_item" /> - </LinearLayout> - <ImageView - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center_horizontal" - android:src="@drawable/cling_arrow_down" /> - </LinearLayout> - - <LinearLayout - android:id="@+id/focused_hotseat_app_bubble" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="bottom|left" - android:layout_marginLeft="25dp" - android:layout_marginBottom="90dp" - android:orientation="vertical" - android:visibility="gone"> - <LinearLayout - android:paddingLeft="20dp" - android:paddingRight="20dp" - android:paddingTop="20dp" - android:paddingBottom="20dp" - android:layout_width="240dp" - android:layout_height="wrap_content" - android:orientation="vertical" - android:background="@drawable/cling"> - <TextView - android:id="@+id/focused_hotseat_app_title" - style="@style/ClingTitleText" - android:layout_width="wrap_content" - android:layout_height="wrap_content" /> - <TextView - android:id="@+id/focused_hotseat_app_description" - style="@style/ClingText" - android:layout_width="match_parent" - android:layout_height="wrap_content" /> - </LinearLayout> - <ImageView - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="left" - android:layout_marginLeft="78dp" - android:src="@drawable/cling_arrow_down" /> - </LinearLayout> - </FrameLayout> - - <Button - style="@style/ClingButton" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginBottom="15dp" - android:layout_marginRight="20dp" - android:layout_gravity="bottom|right" - android:onClick="dismissWorkspaceCling" /> -</com.android.launcher3.Cling> diff --git a/res/layout-sw600dp-port/first_run_cling.xml b/res/layout-sw600dp-port/first_run_cling.xml deleted file mode 100644 index d80c084ab..000000000 --- a/res/layout-sw600dp-port/first_run_cling.xml +++ /dev/null @@ -1,100 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2011 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. ---> -<com.android.launcher3.Cling - xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:launcher="http://schemas.android.com/apk/res-auto/com.android.launcher3" - android:layout_width="match_parent" - android:layout_height="match_parent" - launcher:drawIdentifier="first_run_portrait"> - <FrameLayout - android:id="@+id/content" - android:layout_width="match_parent" - android:layout_height="match_parent"> - <LinearLayout - android:id="@+id/bubble_content" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_gravity="center" - android:layout_marginLeft="100dp" - android:layout_marginRight="100dp" - android:orientation="vertical"> - <TextView - style="@style/ClingAltTitleText" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_gravity="center_horizontal" - android:layout_marginBottom="10dp" - android:text="@string/first_run_cling_title" - android:textColor="#FFFFFFFF" - android:gravity="center" /> - <TextView - style="@style/ClingAltText" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_gravity="center_horizontal" - android:text="@string/first_run_cling_description" - android:textColor="#80000000" - android:gravity="center" /> - </LinearLayout> - <TextView - style="@style/ClingHintText" - android:id="@+id/search_bar_hint" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="top|end" - android:layout_marginEnd="30dp" - android:layout_marginTop="80dp" - android:gravity="center_horizontal" - android:maxWidth="160dp" - android:visibility="gone" - android:drawableTop="@drawable/cling_arrow_up" - android:drawablePadding="10dp" - android:text="@string/first_run_cling_search_bar_hint" /> - <TextView - style="@style/ClingHintText" - android:id="@+id/custom_content_hint" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="top|start" - android:layout_marginStart="30dp" - android:layout_marginTop="120dp" - android:gravity="start" - android:maxWidth="160dp" - android:visibility="gone" - android:drawableStart="@drawable/cling_arrow_start" - android:drawablePadding="10dp" - android:text="@string/first_run_cling_custom_content_hint" /> - <TextView - style="@style/ClingHintText" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="bottom|end" - android:layout_marginEnd="30dp" - android:layout_marginBottom="120dp" - android:maxWidth="180dp" - android:drawableEnd="@drawable/cling_arrow_end" - android:drawablePadding="10dp" - android:text="@string/first_run_cling_create_screens_hint" /> - </FrameLayout> - <Button - style="@style/ClingButton" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginBottom="30dp" - android:layout_marginEnd="30dp" - android:layout_gravity="bottom|end" - android:onClick="dismissFirstRunCling" /> -</com.android.launcher3.Cling> diff --git a/res/layout-sw600dp-port/longpress_cling.xml b/res/layout-sw600dp-port/longpress_cling.xml new file mode 100644 index 000000000..b42d697a5 --- /dev/null +++ b/res/layout-sw600dp-port/longpress_cling.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:launcher="http://schemas.android.com/apk/res-auto/com.android.launcher3" + android:id="@+id/longpress_cling" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:background="@color/cling_scrim_background" + android:orientation="vertical" > + + <Space + android:layout_width="match_parent" + android:layout_height="0dp" + android:layout_weight="1" /> + + <FrameLayout + android:id="@+id/cling_content" + android:layout_width="360dp" + android:layout_height="wrap_content" + android:layout_gravity="center_horizontal" + android:background="@drawable/cling_bg" /> + + <Space + android:layout_width="match_parent" + android:layout_height="0dp" + android:layout_weight="3" /> + +</LinearLayout>
\ No newline at end of file diff --git a/res/layout-sw600dp-port/migration_workspace_cling.xml b/res/layout-sw600dp-port/migration_workspace_cling.xml deleted file mode 100644 index eb13137a1..000000000 --- a/res/layout-sw600dp-port/migration_workspace_cling.xml +++ /dev/null @@ -1,70 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2011 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. ---> -<com.android.launcher3.Cling - xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:launcher="http://schemas.android.com/apk/res-auto/com.android.launcher3" - android:layout_width="match_parent" - android:layout_height="match_parent" - launcher:drawIdentifier="migration_workspace_large_portrait"> - <FrameLayout - android:id="@+id/content" - android:layout_width="480dp" - android:layout_height="match_parent" - android:layout_gravity="bottom|center_horizontal"> - <LinearLayout - android:id="@+id/migration_workspace_cling_bubble" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_gravity="bottom" - android:layout_marginStart="25dp" - android:layout_marginEnd="25dp" - android:orientation="vertical"> - <LinearLayout - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginRight="4dp" - android:paddingLeft="20dp" - android:paddingRight="20dp" - android:paddingTop="20dp" - android:paddingBottom="20dp" - android:orientation="vertical" - android:background="@drawable/cling"> - <TextView - style="@style/ClingTitleText" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:text="@string/workspace_cling_title" /> - <TextView - style="@style/ClingText" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:text="@string/workspace_cling_move_item" /> - </LinearLayout> - <ImageView - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center_horizontal" - android:src="@drawable/cling_arrow_down" /> - <Button - style="@style/ClingButton" - android:id="@+id/dismiss_migration_workspace_cling_button" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="right" - android:onClick="dismissMigrationWorkspaceCling" /> - </LinearLayout> - </FrameLayout> -</com.android.launcher3.Cling> diff --git a/res/layout-sw600dp/first_run_cling.xml b/res/layout-sw600dp/first_run_cling.xml deleted file mode 100644 index 295765b6e..000000000 --- a/res/layout-sw600dp/first_run_cling.xml +++ /dev/null @@ -1,100 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2011 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. ---> -<com.android.launcher3.Cling - xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:launcher="http://schemas.android.com/apk/res-auto/com.android.launcher3" - android:layout_width="match_parent" - android:layout_height="match_parent" - launcher:drawIdentifier="first_run_landscape"> - <FrameLayout - android:id="@+id/content" - android:layout_width="match_parent" - android:layout_height="match_parent"> - <LinearLayout - android:id="@+id/bubble_content" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_gravity="center" - android:layout_marginLeft="100dp" - android:layout_marginRight="100dp" - android:orientation="vertical"> - <TextView - style="@style/ClingAltTitleText" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_gravity="center_horizontal" - android:layout_marginBottom="10dp" - android:text="@string/first_run_cling_title" - android:textColor="#FFFFFFFF" - android:gravity="center" /> - <TextView - style="@style/ClingAltText" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_gravity="center_horizontal" - android:text="@string/first_run_cling_description" - android:textColor="#80000000" - android:gravity="center" /> - </LinearLayout> - <TextView - style="@style/ClingHintText" - android:id="@+id/search_bar_hint" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="top|start" - android:layout_marginStart="60dp" - android:layout_marginTop="105dp" - android:gravity="start" - android:maxWidth="160dp" - android:visibility="gone" - android:drawableStart="@drawable/cling_arrow_start" - android:drawablePadding="10dp" - android:text="@string/first_run_cling_search_bar_hint" /> - <TextView - style="@style/ClingHintText" - android:id="@+id/custom_content_hint" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="top|start" - android:layout_marginStart="60dp" - android:layout_marginTop="200dp" - android:gravity="start" - android:maxWidth="160dp" - android:visibility="gone" - android:drawableStart="@drawable/cling_arrow_start" - android:drawablePadding="10dp" - android:text="@string/first_run_cling_custom_content_hint" /> - <TextView - style="@style/ClingHintText" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="bottom|end" - android:layout_marginEnd="30dp" - android:layout_marginBottom="120dp" - android:maxWidth="180dp" - android:drawableEnd="@drawable/cling_arrow_end" - android:drawablePadding="10dp" - android:text="@string/first_run_cling_create_screens_hint" /> - </FrameLayout> - <Button - style="@style/ClingButton" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginBottom="30dp" - android:layout_marginEnd="30dp" - android:layout_gravity="bottom|end" - android:onClick="dismissFirstRunCling" /> -</com.android.launcher3.Cling> diff --git a/res/layout-sw600dp/folder_cling.xml b/res/layout-sw600dp/folder_cling.xml deleted file mode 100644 index f21aef4e4..000000000 --- a/res/layout-sw600dp/folder_cling.xml +++ /dev/null @@ -1,66 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2011 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. ---> -<com.android.launcher3.Cling - xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:launcher="http://schemas.android.com/apk/res-auto/com.android.launcher3" - launcher:drawIdentifier="folder_large"> - <LinearLayout - android:id="@+id/folder_bubble" - android:layout_width="300dp" - android:layout_height="match_parent" - android:layout_gravity="left|top" - android:paddingTop="28dp" - android:paddingRight="10dp" - android:orientation="vertical"> - <LinearLayout - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:orientation="horizontal"> - <ImageView - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center_vertical" - android:src="@drawable/cling_arrow_start" /> - <LinearLayout - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginRight="4dp" - android:paddingLeft="20dp" - android:paddingRight="20dp" - android:paddingTop="20dp" - android:paddingBottom="20dp" - android:orientation="vertical" - android:background="@drawable/cling"> - <TextView - style="@style/ClingTitleText" - android:id="@+id/folder_cling_title" - android:text="@string/folder_cling_title" /> - <TextView - style="@style/ClingText" - android:id="@+id/folder_cling_create_folder" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:text="@string/folder_cling_create_folder" /> - </LinearLayout> - </LinearLayout> - <Button - style="@style/ClingButton" - android:id="@+id/cling_dismiss" - android:layout_marginTop="5dp" - android:layout_gravity="right" - android:onClick="dismissFolderCling" /> - </LinearLayout> -</com.android.launcher3.Cling> diff --git a/res/layout-sw600dp/migration_cling.xml b/res/layout-sw600dp/migration_cling.xml deleted file mode 100644 index 19def6a56..000000000 --- a/res/layout-sw600dp/migration_cling.xml +++ /dev/null @@ -1,98 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2011 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. ---> -<com.android.launcher3.Cling - xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:launcher="http://schemas.android.com/apk/res-auto/com.android.launcher3" - android:layout_width="match_parent" - android:layout_height="match_parent" - launcher:drawIdentifier="migration_portrait"> - <LinearLayout - android:id="@+id/content" - android:layout_width="360dp" - android:layout_height="wrap_content" - android:layout_gravity="center" - android:orientation="vertical"> - - <LinearLayout - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_gravity="top" - android:layout_marginBottom="15dp" - android:orientation="vertical"> - <TextView - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:gravity="center" - android:text="@string/first_run_cling_title" - android:textSize="42dp" - android:textColor="#FFffffff" /> - <ImageView - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginTop="10dp" - android:layout_marginBottom="0dp" - android:layout_gravity="center_horizontal" - android:src="@drawable/on_boarding_welcome" /> - - <ImageView - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center_horizontal" - android:src="@drawable/cling_arrow_up" /> - <LinearLayout - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginLeft="4dp" - android:layout_marginRight="4dp" - android:paddingLeft="25dp" - android:paddingRight="25dp" - android:paddingTop="20dp" - android:paddingBottom="20dp" - android:orientation="vertical" - android:background="@drawable/cling"> - <TextView - style="@style/ClingTitleText" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:text="@string/migration_cling_title" /> - <TextView - style="@style/ClingText" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:text="@string/migration_cling_description" /> - </LinearLayout> - </LinearLayout> - - <LinearLayout - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_gravity="bottom" - android:orientation="vertical"> - <Button - style="@style/ClingButton" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:text="@string/migration_cling_copy_apps" - android:onClick="dismissMigrationClingCopyApps" /> - <Button - style="@style/ClingButton" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:text="@string/migration_cling_use_default" - android:onClick="dismissMigrationClingUseDefault" /> - </LinearLayout> - </LinearLayout> -</com.android.launcher3.Cling> diff --git a/res/layout-sw600dp/workspace_cling.xml b/res/layout-sw600dp/workspace_cling.xml deleted file mode 100644 index 63b5522ca..000000000 --- a/res/layout-sw600dp/workspace_cling.xml +++ /dev/null @@ -1,65 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2011 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. ---> -<com.android.launcher3.Cling - xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:launcher="http://schemas.android.com/apk/res-auto/com.android.launcher3" - android:layout_width="match_parent" - android:layout_height="match_parent" - launcher:drawIdentifier="workspace_large"> - <FrameLayout - android:id="@+id/content" - android:layout_width="match_parent" - android:layout_height="match_parent"> - <LinearLayout - android:id="@+id/workspace_cling_bubble" - android:layout_width="400dp" - android:layout_height="wrap_content" - android:layout_gravity="center_horizontal|bottom" - android:orientation="vertical"> - <LinearLayout - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:paddingLeft="20dp" - android:paddingRight="20dp" - android:paddingTop="20dp" - android:paddingBottom="20dp" - android:orientation="vertical" - android:background="@drawable/cling"> - <TextView - style="@style/ClingTitleText" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:text="@string/workspace_cling_title" /> - <TextView - style="@style/ClingText" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:text="@string/workspace_cling_move_item" /> - </LinearLayout> - <ImageView - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center_horizontal" - android:src="@drawable/cling_arrow_down" /> - <Button - style="@style/ClingButton" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="right" - android:onClick="dismissWorkspaceCling" /> - </LinearLayout> - </FrameLayout> -</com.android.launcher3.Cling> diff --git a/res/layout-sw720dp/first_run_cling.xml b/res/layout-sw720dp/first_run_cling.xml deleted file mode 100644 index c43d8d32e..000000000 --- a/res/layout-sw720dp/first_run_cling.xml +++ /dev/null @@ -1,98 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2011 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. ---> -<com.android.launcher3.Cling - xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:launcher="http://schemas.android.com/apk/res-auto/com.android.launcher3" - android:layout_width="match_parent" - android:layout_height="match_parent" - launcher:drawIdentifier="first_run_portrait"> - <FrameLayout - android:id="@+id/content" - android:layout_width="match_parent" - android:layout_height="match_parent"> - <LinearLayout - android:id="@+id/bubble_content" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_gravity="center" - android:layout_marginLeft="100dp" - android:layout_marginRight="100dp" - android:orientation="vertical"> - <TextView - style="@style/ClingAltTitleText" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_gravity="center_horizontal" - android:layout_marginBottom="10dp" - android:text="@string/first_run_cling_title" - android:textColor="#FFFFFFFF" - android:gravity="center" /> - <TextView - style="@style/ClingAltText" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_gravity="center_horizontal" - android:text="@string/first_run_cling_description" - android:textColor="#80000000" - android:gravity="center" /> - </LinearLayout> - <TextView - style="@style/ClingHintText" - android:id="@+id/search_bar_hint" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="top|end" - android:layout_marginEnd="120dp" - android:layout_marginTop="80dp" - android:gravity="center_horizontal" - android:maxWidth="160dp" - android:visibility="gone" - android:drawableTop="@drawable/cling_arrow_up" - android:drawablePadding="10dp" - android:text="@string/first_run_cling_search_bar_hint" /> - <TextView - style="@style/ClingHintText" - android:id="@+id/custom_content_hint" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center_vertical|start" - android:layout_marginStart="30dp" - android:gravity="start" - android:maxWidth="160dp" - android:visibility="gone" - android:drawableStart="@drawable/cling_arrow_start" - android:drawablePadding="10dp" - android:text="@string/first_run_cling_custom_content_hint" /> - <TextView - style="@style/ClingHintText" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center_vertical|end" - android:layout_marginEnd="30dp" - android:maxWidth="180dp" - android:drawableEnd="@drawable/cling_arrow_end" - android:drawablePadding="10dp" - android:text="@string/first_run_cling_create_screens_hint" /> - </FrameLayout> - <Button - style="@style/ClingButton" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginBottom="30dp" - android:layout_marginEnd="40dp" - android:layout_gravity="bottom|end" - android:onClick="dismissFirstRunCling" /> -</com.android.launcher3.Cling> diff --git a/res/layout-sw720dp/launcher.xml b/res/layout-sw720dp/launcher.xml index 685d03c6f..62615411f 100644 --- a/res/layout-sw720dp/launcher.xml +++ b/res/layout-sw720dp/launcher.xml @@ -30,6 +30,11 @@ android:layout_height="match_parent" android:fitsSystemWindows="true"> + <com.android.launcher3.FocusIndicatorView + android:id="@+id/focus_indicator" + android:layout_width="52dp" + android:layout_height="52dp" /> + <!-- The workspace contains 5 screens of cells --> <com.android.launcher3.Workspace android:id="@+id/workspace" @@ -61,40 +66,6 @@ android:layout_height="wrap_content" android:layout_gravity="center_horizontal" /> - <!-- The Workspace cling must appear under the AppsCustomizePagedView below to ensure - that it is still visible during the transition to AllApps and doesn't overlay on - top of that view. --> - <com.android.launcher3.ScrimView - android:id="@+id/cling_scrim" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:visibility="gone" /> - <include layout="@layout/first_run_cling" - android:id="@+id/first_run_cling" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:visibility="gone" /> - <include layout="@layout/migration_cling" - android:id="@+id/migration_cling" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:visibility="gone" /> - <include layout="@layout/migration_workspace_cling" - android:id="@+id/migration_workspace_cling" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:visibility="gone" /> - <include layout="@layout/workspace_cling" - android:id="@+id/workspace_cling" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:visibility="gone" /> - <include layout="@layout/folder_cling" - android:id="@+id/folder_cling" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:visibility="gone" /> - <com.android.launcher3.DrawableStateProxyView android:id="@+id/voice_button_proxy" android:layout_width="0dp" diff --git a/res/layout-sw720dp/migration_workspace_cling.xml b/res/layout-sw720dp/migration_workspace_cling.xml deleted file mode 100644 index eb13137a1..000000000 --- a/res/layout-sw720dp/migration_workspace_cling.xml +++ /dev/null @@ -1,70 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2011 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. ---> -<com.android.launcher3.Cling - xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:launcher="http://schemas.android.com/apk/res-auto/com.android.launcher3" - android:layout_width="match_parent" - android:layout_height="match_parent" - launcher:drawIdentifier="migration_workspace_large_portrait"> - <FrameLayout - android:id="@+id/content" - android:layout_width="480dp" - android:layout_height="match_parent" - android:layout_gravity="bottom|center_horizontal"> - <LinearLayout - android:id="@+id/migration_workspace_cling_bubble" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_gravity="bottom" - android:layout_marginStart="25dp" - android:layout_marginEnd="25dp" - android:orientation="vertical"> - <LinearLayout - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginRight="4dp" - android:paddingLeft="20dp" - android:paddingRight="20dp" - android:paddingTop="20dp" - android:paddingBottom="20dp" - android:orientation="vertical" - android:background="@drawable/cling"> - <TextView - style="@style/ClingTitleText" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:text="@string/workspace_cling_title" /> - <TextView - style="@style/ClingText" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:text="@string/workspace_cling_move_item" /> - </LinearLayout> - <ImageView - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center_horizontal" - android:src="@drawable/cling_arrow_down" /> - <Button - style="@style/ClingButton" - android:id="@+id/dismiss_migration_workspace_cling_button" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="right" - android:onClick="dismissMigrationWorkspaceCling" /> - </LinearLayout> - </FrameLayout> -</com.android.launcher3.Cling> diff --git a/res/layout/all_apps_button.xml b/res/layout/all_apps_button.xml index 1b9ea082f..9d6d82bb2 100644 --- a/res/layout/all_apps_button.xml +++ b/res/layout/all_apps_button.xml @@ -16,5 +16,4 @@ <TextView xmlns:android="http://schemas.android.com/apk/res/android" style="@style/WorkspaceIcon" - android:focusable="true" - android:background="@drawable/focusable_view_bg" /> + android:focusable="true" /> diff --git a/res/layout/application.xml b/res/layout/application.xml index e4909ddad..c21dea070 100644 --- a/res/layout/application.xml +++ b/res/layout/application.xml @@ -16,5 +16,4 @@ <com.android.launcher3.BubbleTextView xmlns:android="http://schemas.android.com/apk/res/android" style="@style/WorkspaceIcon" - android:focusable="true" - android:background="@drawable/focusable_view_bg" /> + android:focusable="true" /> diff --git a/res/layout/apps_customize_application.xml b/res/layout/apps_customize_application.xml index 3b0fa6f4e..c56cdf3d2 100644 --- a/res/layout/apps_customize_application.xml +++ b/res/layout/apps_customize_application.xml @@ -14,15 +14,8 @@ limitations under the License. --> -<com.android.launcher3.PagedViewIcon +<com.android.launcher3.BubbleTextView xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:launcher="http://schemas.android.com/apk/res-auto/com.android.launcher3" - style="@style/WorkspaceIcon.AppsCustomize" - android:id="@+id/application_icon" - android:layout_width="match_parent" - android:layout_height="match_parent" - - android:focusable="true" - android:background="@drawable/focusable_view_bg" /> + android:focusable="true" /> diff --git a/res/layout/apps_customize_pane.xml b/res/layout/apps_customize_pane.xml index eae216e93..bf5f71b90 100644 --- a/res/layout/apps_customize_pane.xml +++ b/res/layout/apps_customize_pane.xml @@ -16,64 +16,47 @@ <com.android.launcher3.AppsCustomizeTabHost xmlns:android="http://schemas.android.com/apk/res/android" xmlns:launcher="http://schemas.android.com/apk/res-auto/com.android.launcher3" - android:background="#80FFFFFF"> + android:clipChildren="false"> + <LinearLayout - android:id="@+id/apps_customize_content" - android:orientation="vertical" + android:id="@+id/content" android:layout_width="match_parent" android:layout_height="match_parent" - android:visibility="gone"> - <!-- The layout_width of the tab bar gets overriden to align the content - with the text in the tabs in AppsCustomizeTabHost. --> + android:clipChildren="false" + android:orientation="vertical"> + <FrameLayout - android:id="@+id/tabs_container" - android:layout_width="wrap_content" - android:layout_height="@dimen/apps_customize_tab_bar_height" - android:layout_marginTop="@dimen/apps_customize_tab_bar_margin_top" - android:layout_gravity="center_horizontal" - android:visibility="gone"> - <com.android.launcher3.FocusOnlyTabWidget - android:id="@android:id/tabs" + android:layout_width="match_parent" + android:layout_height="0dp" + android:layout_weight="1" + android:clipChildren="false"> + <FrameLayout + android:id="@+id/fake_page_container" android:layout_width="match_parent" android:layout_height="match_parent" - android:layout_gravity="center" - android:gravity="start" - android:background="@drawable/tab_unselected_holo" - android:tabStripEnabled="false" - android:divider="@null" /> - <include - android:id="@+id/market_button" - layout="@layout/market_button" - android:layout_width="wrap_content" - android:layout_height="match_parent" - android:layout_gravity="end" /> - </FrameLayout> - <FrameLayout - android:id="@android:id/tabcontent" - android:layout_width="match_parent" - android:layout_height="match_parent"> + android:clipChildren="false" + android:clipToPadding="false"> + <FrameLayout + android:id="@+id/fake_page" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:visibility="invisible" + android:clipToPadding="false" /> + </FrameLayout> <com.android.launcher3.AppsCustomizePagedView android:id="@+id/apps_customize_pane_content" android:layout_width="match_parent" android:layout_height="match_parent" launcher:widgetCountX="@integer/apps_customize_widget_cell_count_x" launcher:widgetCountY="@integer/apps_customize_widget_cell_count_y" - launcher:clingFocusedX="@integer/apps_customize_cling_focused_x" - launcher:clingFocusedY="@integer/apps_customize_cling_focused_y" launcher:maxGap="@dimen/workspace_max_gap" launcher:pageIndicator="@+id/apps_customize_page_indicator" /> - <FrameLayout - android:id="@+id/animation_buffer" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:background="#FF000000" - android:visibility="gone" /> - <include - android:id="@+id/apps_customize_page_indicator" - layout="@layout/page_indicator" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center_horizontal|bottom" /> </FrameLayout> + <include + android:id="@+id/apps_customize_page_indicator" + layout="@layout/page_indicator" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center" /> </LinearLayout> </com.android.launcher3.AppsCustomizeTabHost> diff --git a/res/layout/apps_customize_widget.xml b/res/layout/apps_customize_widget.xml index 7c98b4a9b..e299b32b0 100644 --- a/res/layout/apps_customize_widget.xml +++ b/res/layout/apps_customize_widget.xml @@ -25,24 +25,45 @@ android:background="@drawable/focusable_view_bg" android:focusable="true"> - <!-- The preview of the widget or shortcut. --> - <com.android.launcher3.PagedViewWidgetImageView - android:id="@+id/widget_preview" - style="@style/PagedViewWidgetImageView" + <LinearLayout + android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_weight="1" - android:paddingTop="@dimen/app_widget_preview_padding_top" - android:paddingEnd="@dimen/app_widget_preview_padding_right" - android:paddingRight="@dimen/app_widget_preview_padding_right" - android:scaleType="matrix" - android:background="@drawable/screenpanel" /> + android:layout_weight="1"> + <FrameLayout + android:id="@+id/left_border" + android:layout_width="1dp" + android:layout_height="match_parent" + android:background="@color/widget_text_panel" + android:visibility="gone" /> + + <!-- The preview of the widget or shortcut. --> + <com.android.launcher3.PagedViewWidgetImageView + android:id="@+id/widget_preview" + style="@style/PagedViewWidgetImageView" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:layout_weight="1" + android:paddingTop="@dimen/app_widget_preview_padding_top" + android:paddingEnd="@dimen/app_widget_preview_padding_right" + android:paddingRight="@dimen/app_widget_preview_padding_right" + android:scaleType="matrix" /> + <FrameLayout + android:id="@+id/right_border" + android:layout_width="1dp" + android:layout_height="match_parent" + android:background="@color/widget_text_panel" + android:visibility="gone" /> + </LinearLayout> + <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginTop="@dimen/app_widget_preview_label_margin_top" - android:layout_marginStart="@dimen/app_widget_preview_label_margin_left" - android:layout_marginEnd="@dimen/app_widget_preview_label_margin_right" + android:paddingTop="@dimen/app_widget_preview_label_vertical_padding" + android:paddingBottom="@dimen/app_widget_preview_label_vertical_padding" + android:paddingLeft="@dimen/app_widget_preview_label_horizontal_padding" + android:paddingRight="@dimen/app_widget_preview_label_horizontal_padding" + android:background="@color/widget_text_panel" android:orientation="horizontal"> <!-- The name of the widget. --> <TextView xmlns:android="http://schemas.android.com/apk/res/android" @@ -56,7 +77,7 @@ android:fadingEdge="horizontal" android:textColor="#FFFFFFFF" - android:textSize="13sp" + android:textSize="12sp" android:textAlignment="viewStart" android:fontFamily="sans-serif-condensed" android:shadowRadius="2.0" @@ -73,7 +94,7 @@ android:layout_weight="0" android:gravity="start" - android:textColor="#FFAAAAAA" + android:textColor="#FFFFFFFF" android:textSize="12sp" android:fontFamily="sans-serif-condensed" android:shadowRadius="2.0" diff --git a/res/values-sw340dp-land/dimens.xml b/res/layout/appwidget_not_ready.xml index 7901dc47d..be7c33b36 100644 --- a/res/values-sw340dp-land/dimens.xml +++ b/res/layout/appwidget_not_ready.xml @@ -1,5 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 201 The Android Open Source Project +<!-- + Copyright (C) 2009 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. @@ -14,7 +15,6 @@ limitations under the License. --> -<resources> -<!-- Clings --> - <dimen name="folderClingMarginTop">50dp</dimen> -</resources> +<View xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent" /> diff --git a/res/layout/custom_content_page_indicator_marker.xml b/res/layout/custom_content_page_indicator_marker.xml deleted file mode 100644 index 8fe3f8fdf..000000000 --- a/res/layout/custom_content_page_indicator_marker.xml +++ /dev/null @@ -1,39 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2013 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. ---> -<com.android.launcher3.PageIndicatorMarker - xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:launcher="http://schemas.android.com/apk/res-auto/com.android.launcher3" - android:layout_width="16dp" - android:layout_height="16dp" - android:layout_gravity="center_vertical"> - <ImageView - android:id="@+id/inactive" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:scaleType="centerInside" - android:src="@drawable/custom_content_page" - /> - <ImageView - android:id="@+id/active" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:scaleType="centerInside" - android:src="@drawable/custom_content_page" - android:alpha="0" - android:scaleX="0.5" - android:scaleY="0.5" - /> -</com.android.launcher3.PageIndicatorMarker> diff --git a/res/drawable/cling_arrow_end.xml b/res/layout/folder_application.xml index 3f63c7d24..b48b61331 100644 --- a/res/drawable/cling_arrow_end.xml +++ b/res/layout/folder_application.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2013 The Android Open Source Project +<!-- Copyright (C) 2014 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. @@ -13,7 +13,7 @@ See the License for the specific language governing permissions and limitations under the License. --> -<bitmap xmlns:android="http://schemas.android.com/apk/res/android" - android:src="@drawable/cling_arrow_right" - android:autoMirrored="true"> -</bitmap> + +<com.android.launcher3.BubbleTextView xmlns:android="http://schemas.android.com/apk/res/android" + style="@style/WorkspaceIcon.Folder" + android:focusable="true" /> diff --git a/res/layout/folder_icon.xml b/res/layout/folder_icon.xml index 5147f9960..fd45d7685 100644 --- a/res/layout/folder_icon.xml +++ b/res/layout/folder_icon.xml @@ -19,8 +19,7 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" - android:focusable="true" - android:background="@drawable/focusable_view_bg"> + android:focusable="true" > <ImageView android:id="@+id/preview_background" android:layout_gravity="center_horizontal" diff --git a/res/layout/longpress_cling_content.xml b/res/layout/longpress_cling_content.xml new file mode 100644 index 000000000..47a8e9797 --- /dev/null +++ b/res/layout/longpress_cling_content.xml @@ -0,0 +1,43 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical" + android:paddingBottom="24dp" + android:paddingTop="36dp" > + + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:paddingLeft="36dp" + android:paddingRight="36dp" + android:text="@string/workspace_cling_longpress_title" + android:textColor="#E1000000" + android:textSize="24sp" /> + + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="16dp" + android:paddingLeft="36dp" + android:paddingRight="36dp" + android:text="@string/workspace_cling_longpress_description" + android:textColor="#99000000" + android:textSize="16sp" /> + + <Button + android:id="@+id/cling_dismiss_longpress_info" + style="?android:attr/buttonBarButtonStyle" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="end" + android:layout_marginRight="12dp" + android:layout_marginTop="27dp" + android:fontFamily="sans-serif-medium" + android:paddingLeft="24dp" + android:paddingRight="24dp" + android:text="@string/workspace_cling_longpress_dismiss" + android:textColor="#FFFFFFFF" + android:textSize="14sp" /> + +</LinearLayout>
\ No newline at end of file diff --git a/res/layout/longpress_cling_welcome_content.xml b/res/layout/longpress_cling_welcome_content.xml new file mode 100644 index 000000000..dd4f8d767 --- /dev/null +++ b/res/layout/longpress_cling_welcome_content.xml @@ -0,0 +1,54 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical" + android:paddingBottom="24dp" + android:paddingTop="36dp" > + + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginBottom="8dp" + android:paddingLeft="36dp" + android:paddingRight="36dp" + android:text="@string/first_run_cling_title" + android:textColor="#E1000000" + android:textSize="34sp" /> + + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginBottom="5.3dp" + android:fontFamily="sans-serif-medium" + android:paddingLeft="36dp" + android:paddingRight="36dp" + android:text="@string/workspace_cling_longpress_title" + android:textColor="#E1000000" + android:textSize="20sp" /> + + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:paddingLeft="36dp" + android:paddingRight="36dp" + android:text="@string/workspace_cling_longpress_description" + android:textColor="#99000000" + android:textSize="16sp" /> + + <Button + android:id="@+id/cling_dismiss_longpress_info" + style="?android:attr/buttonBarButtonStyle" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="end" + android:layout_marginRight="12dp" + android:layout_marginTop="27dp" + android:fontFamily="sans-serif-medium" + android:paddingLeft="24dp" + android:paddingRight="24dp" + android:text="@string/workspace_cling_longpress_dismiss" + android:textColor="#FFFFFFFF" + android:textSize="14sp" /> + +</LinearLayout>
\ No newline at end of file diff --git a/res/layout/user_folder.xml b/res/layout/user_folder.xml index 5d5f33b1f..4e5303ac0 100644 --- a/res/layout/user_folder.xml +++ b/res/layout/user_folder.xml @@ -20,7 +20,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" - android:background="@drawable/portal_container_holo"> + android:background="@drawable/quantum_panel"> <ScrollView android:id="@+id/scroll_view" diff --git a/res/values-af/strings.xml b/res/values-af/strings.xml index b5c17c5d1..4a4bb78a2 100644 --- a/res/values-af/strings.xml +++ b/res/values-af/strings.xml @@ -24,6 +24,7 @@ <string name="uid_name" msgid="7820867637514617527">"Android-kernprogramme"</string> <string name="folder_name" msgid="7371454440695724752"></string> <string name="activity_not_found" msgid="8071924732094499514">"Program is nie geïnstalleer nie."</string> + <string name="safemode_shortcut_error" msgid="9160126848219158407">"Afgelaaide program in veiligmodus gedeaktiveer"</string> <string name="widgets_tab_label" msgid="2921133187116603919">"Legstukke"</string> <string name="widget_adder" msgid="3201040140710381657">"Legstukke"</string> <string name="toggle_weight_watcher" msgid="5645299835184636119">"Wys Mem"</string> @@ -76,6 +77,7 @@ <string name="permlab_write_settings" msgid="3574213698004620587">"skryf Tuis-instellings en -kortpaaie"</string> <string name="permdesc_write_settings" msgid="5440712911516509985">"Laat die program toe om die instellings en kortpaaie in Tuis te verander."</string> <string name="gadget_error_text" msgid="6081085226050792095">"Kon nie legstuk laai nie"</string> + <string name="gadget_setup_text" msgid="8274003207686040488">"Stel op"</string> <string name="uninstall_system_app_text" msgid="4172046090762920660">"Dit is \'n stelselprogram en kan nie gedeïnstalleer word nie."</string> <string name="dream_name" msgid="1530253749244328964">"Vuurpyllanseerder"</string> <string name="folder_hint_text" msgid="6617836969016293992">"Naamlose vouer"</string> @@ -95,6 +97,9 @@ <string name="migration_cling_use_default" msgid="2626475813981258626">"BEGIN VAN NUUTS AF"</string> <string name="workspace_cling_title" msgid="5626202359865825661">"Organiseer jou spasie"</string> <string name="workspace_cling_move_item" msgid="528201129978005352">"Raak en hou agtergrond om muurpapier, legstukke en instellings te bestuur."</string> + <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Muurpapiere, legstukke en instellings"</string> + <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"Raak en hou agtergrond om te pasmaak"</string> + <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"HET DIT"</string> <string name="folder_cling_title" msgid="3894908818693254164">"Hier\'s \'n vouer"</string> <string name="folder_cling_create_folder" msgid="6158215559475836131">"Om een soos dié te skep, raak en hou \'n program en skuif dit dan oor \'n ander een."</string> <string name="cling_dismiss" msgid="8962359497601507581">"OK"</string> @@ -107,4 +112,14 @@ <string name="widget_button_text" msgid="2880537293434387943">"Legstukke"</string> <string name="wallpaper_button_text" msgid="8404103075899945851">"Muurpapiere"</string> <string name="settings_button_text" msgid="8119458837558863227">"Instellings"</string> + <string name="package_state_enqueued" msgid="6227252464303085641">"Wag tans…"</string> + <string name="package_state_downloading" msgid="4088770468458724721">"Laai tans af…"</string> + <string name="package_state_installing" msgid="7588193972189849870">"Installeer tans…"</string> + <string name="package_state_unknown" msgid="7592128424511031410">"Onbekend"</string> + <string name="package_state_error" msgid="7672093962724223588">"Nie teruggestel nie"</string> + <string name="abandoned_clean_all" msgid="5256770727689657618">"Verwyder almal"</string> + <string name="abandoned_clean_this" msgid="7610119707847920412">"Verwyder"</string> + <string name="abandoned_search" msgid="891119232568284442">"Soek"</string> + <string name="abandoned_promises_title" msgid="7096178467971716750">"Hierdie program is nie geïnstalleer nie"</string> + <string name="abandoned_promise_explanation" msgid="3990027586878167529">"Die program vir hierdie ikoon is nie geïnstalleer nie. Jy kan dit verwyder of die program soek en dit self installeer."</string> </resources> diff --git a/res/values-am/strings.xml b/res/values-am/strings.xml index ce9fb9b39..25931db7d 100644 --- a/res/values-am/strings.xml +++ b/res/values-am/strings.xml @@ -24,6 +24,7 @@ <string name="uid_name" msgid="7820867637514617527">"Android ዋና መተግበሪያዎች"</string> <string name="folder_name" msgid="7371454440695724752"></string> <string name="activity_not_found" msgid="8071924732094499514">"መተግበሪያ አልተጫነም።"</string> + <string name="safemode_shortcut_error" msgid="9160126848219158407">"የወረደው መተግበሪያ ደህንነቱ በተጠበቀ ሁኔታ ውስጥ ተሰናክሏል"</string> <string name="widgets_tab_label" msgid="2921133187116603919">"ፍርግሞች"</string> <string name="widget_adder" msgid="3201040140710381657">"ፍርግሞች"</string> <string name="toggle_weight_watcher" msgid="5645299835184636119">"ማህደረ ማስታወሻ አሳይ"</string> @@ -76,6 +77,7 @@ <string name="permlab_write_settings" msgid="3574213698004620587">"የመነሻ ቅንብሮችን እና አቋራጮችን ይጽፋል"</string> <string name="permdesc_write_settings" msgid="5440712911516509985">"መተግብሪያው ቅንብሮችን እና አቋራጮችን በመነሻ ውስጥ እንዲቀይራቸው ያስችለዋል።"</string> <string name="gadget_error_text" msgid="6081085226050792095">"ፍርግም የመጫን ችግር"</string> + <string name="gadget_setup_text" msgid="8274003207686040488">"ማዋቀሪያ"</string> <string name="uninstall_system_app_text" msgid="4172046090762920660">"ይህ የስርዓት መተግበሪያ ነው እና ማራገፍ አይቻልም።"</string> <string name="dream_name" msgid="1530253749244328964">"የሮኬት ማስጀመሪያ"</string> <string name="folder_hint_text" msgid="6617836969016293992">"ስም-አልባ አቃፊ"</string> @@ -94,7 +96,10 @@ <string name="migration_cling_copy_apps" msgid="946331230090919440">"አዶዎችን ይቅዱ"</string> <string name="migration_cling_use_default" msgid="2626475813981258626">"እንደ አዲስ ይጀምሩ"</string> <string name="workspace_cling_title" msgid="5626202359865825661">"ቦታዎን ያደራጁ"</string> - <string name="workspace_cling_move_item" msgid="528201129978005352">"የግድግዳ ወረቀት፣ ምግብሮችን እና ቅንብሮችን ለማቀናበር ጀርባውን ይንኩ እና ይያዙት።"</string> + <string name="workspace_cling_move_item" msgid="528201129978005352">"ልጣፍ ፣ ምግብሮችን እና ቅንብሮችን ለማቀናበር ጀርባውን ይንኩ እና ይያዙት።"</string> + <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"የግድግዳ ወረቀቶች፣ ንዑስ ፕሮግራሞች እና ቅንብሮች"</string> + <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"ለማበጀት ጀርባውን ነክተው ይያዙት"</string> + <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"ገባኝ"</string> <string name="folder_cling_title" msgid="3894908818693254164">"አንድ አቃፊ እነሆ"</string> <string name="folder_cling_create_folder" msgid="6158215559475836131">"አንድ እንደዚህ አይነት ለመፍጠር መተግበሪያውን ነክተው ይያዙት እና ወደ ሌላ ያንቀሳቅሱት።"</string> <string name="cling_dismiss" msgid="8962359497601507581">"እሺ"</string> @@ -107,4 +112,14 @@ <string name="widget_button_text" msgid="2880537293434387943">"ፍርግሞች"</string> <string name="wallpaper_button_text" msgid="8404103075899945851">"የግድግዳ ወረቀቶች"</string> <string name="settings_button_text" msgid="8119458837558863227">"ቅንብሮች"</string> + <string name="package_state_enqueued" msgid="6227252464303085641">"በመጠበቅ ላይ"</string> + <string name="package_state_downloading" msgid="4088770468458724721">"በማውረድ ላይ"</string> + <string name="package_state_installing" msgid="7588193972189849870">"በመጫን ላይ"</string> + <string name="package_state_unknown" msgid="7592128424511031410">"የማይታወቅ"</string> + <string name="package_state_error" msgid="7672093962724223588">"ወደነበረበት አልተመለሰም"</string> + <string name="abandoned_clean_all" msgid="5256770727689657618">"ሁሉንም አስወግድ"</string> + <string name="abandoned_clean_this" msgid="7610119707847920412">"አስወግድ"</string> + <string name="abandoned_search" msgid="891119232568284442">"ፈልግ"</string> + <string name="abandoned_promises_title" msgid="7096178467971716750">"ይህ መተግበሪያ አልተጫነም"</string> + <string name="abandoned_promise_explanation" msgid="3990027586878167529">"የዚህ አዶ መተግበሪያ አልተጫነም። ማስወገድ ወይም መተግበሪያውን መፈለግና ራስዎ መጫን ይችላሉ።"</string> </resources> diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml index 7eb37d3e9..8b6aa025c 100644 --- a/res/values-ar/strings.xml +++ b/res/values-ar/strings.xml @@ -24,6 +24,7 @@ <string name="uid_name" msgid="7820867637514617527">"تطبيقات Android الأساسية"</string> <string name="folder_name" msgid="7371454440695724752"></string> <string name="activity_not_found" msgid="8071924732094499514">"لم يتم تثبيت التطبيق."</string> + <string name="safemode_shortcut_error" msgid="9160126848219158407">"تم تعطيل التطبيق الذي تم تنزيله في الوضع الآمن"</string> <string name="widgets_tab_label" msgid="2921133187116603919">"الأدوات"</string> <string name="widget_adder" msgid="3201040140710381657">"الأدوات"</string> <string name="toggle_weight_watcher" msgid="5645299835184636119">"عرض الذاكرة"</string> @@ -76,6 +77,7 @@ <string name="permlab_write_settings" msgid="3574213698004620587">"كتابة إعدادات واختصارات الشاشة الرئيسية"</string> <string name="permdesc_write_settings" msgid="5440712911516509985">"للسماح للتطبيق بتغيير الإعدادات والاختصارات في الشاشة الرئيسية."</string> <string name="gadget_error_text" msgid="6081085226050792095">"حدثت مشكلة أثناء تحميل الأداة"</string> + <string name="gadget_setup_text" msgid="8274003207686040488">"الإعداد"</string> <string name="uninstall_system_app_text" msgid="4172046090762920660">"هذا تطبيق نظام وتتعذر إزالته."</string> <string name="dream_name" msgid="1530253749244328964">"قاذفة صواريخ"</string> <string name="folder_hint_text" msgid="6617836969016293992">"مجلد بدون اسم"</string> @@ -95,6 +97,9 @@ <string name="migration_cling_use_default" msgid="2626475813981258626">"بداية جديدة"</string> <string name="workspace_cling_title" msgid="5626202359865825661">"تنظيم مساحتك"</string> <string name="workspace_cling_move_item" msgid="528201129978005352">"المس مع الاستمرار الجزء الخلفي من صورة الشاشة لإدارة الخلفية والأدوات والإعدادات."</string> + <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"الخلفيات والأدوات والإعدادات"</string> + <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"المس مع الاستمرار الخلفية لتخصيصها"</string> + <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"حسنًا"</string> <string name="folder_cling_title" msgid="3894908818693254164">"إليك المجلد"</string> <string name="folder_cling_create_folder" msgid="6158215559475836131">"لإنشاء مجلد مثل هذا، المس أحد التطبيقات مع استمرار اللمس، ثم حركه فوق آخر."</string> <string name="cling_dismiss" msgid="8962359497601507581">"موافق"</string> @@ -107,4 +112,14 @@ <string name="widget_button_text" msgid="2880537293434387943">"الأدوات"</string> <string name="wallpaper_button_text" msgid="8404103075899945851">"الخلفيات"</string> <string name="settings_button_text" msgid="8119458837558863227">"الإعدادات"</string> + <string name="package_state_enqueued" msgid="6227252464303085641">"انتظار"</string> + <string name="package_state_downloading" msgid="4088770468458724721">"جارٍ التنزيل"</string> + <string name="package_state_installing" msgid="7588193972189849870">"جارٍ التثبيت"</string> + <string name="package_state_unknown" msgid="7592128424511031410">"غير معروفة"</string> + <string name="package_state_error" msgid="7672093962724223588">"استعادة مخفقة"</string> + <string name="abandoned_clean_all" msgid="5256770727689657618">"إزالة الكل"</string> + <string name="abandoned_clean_this" msgid="7610119707847920412">"إزالة"</string> + <string name="abandoned_search" msgid="891119232568284442">"بحث"</string> + <string name="abandoned_promises_title" msgid="7096178467971716750">"لم يتم تثبيت هذا التطبيق"</string> + <string name="abandoned_promise_explanation" msgid="3990027586878167529">"لم يتم تثبيت تطبيق لهذا الرمز. يمكنك إزالته أو البحث عن التطبيق وتثبيته يدويًا."</string> </resources> diff --git a/res/values-bg/strings.xml b/res/values-bg/strings.xml index 13c011859..dcd193050 100644 --- a/res/values-bg/strings.xml +++ b/res/values-bg/strings.xml @@ -24,6 +24,7 @@ <string name="uid_name" msgid="7820867637514617527">"Основни приложения на Android"</string> <string name="folder_name" msgid="7371454440695724752"></string> <string name="activity_not_found" msgid="8071924732094499514">"Приложението не е инсталирано."</string> + <string name="safemode_shortcut_error" msgid="9160126848219158407">"Изтегленото приложение е деактивирано в безопасния режим"</string> <string name="widgets_tab_label" msgid="2921133187116603919">"Приспособления"</string> <string name="widget_adder" msgid="3201040140710381657">"Приспособления"</string> <string name="toggle_weight_watcher" msgid="5645299835184636119">"Показване на паметта"</string> @@ -76,6 +77,7 @@ <string name="permlab_write_settings" msgid="3574213698004620587">"запис на настройките и преките пътища в Начало"</string> <string name="permdesc_write_settings" msgid="5440712911516509985">"Разрешава на приложението да променя настройките и преките пътища в Начало."</string> <string name="gadget_error_text" msgid="6081085226050792095">"Проблем при зареждане на приспособлението"</string> + <string name="gadget_setup_text" msgid="8274003207686040488">"Настройване"</string> <string name="uninstall_system_app_text" msgid="4172046090762920660">"Това е системно приложение и не може да се деинсталира."</string> <string name="dream_name" msgid="1530253749244328964">"Ракетна площадка"</string> <string name="folder_hint_text" msgid="6617836969016293992">"Папка без име"</string> @@ -95,6 +97,9 @@ <string name="migration_cling_use_default" msgid="2626475813981258626">"СТАРТИРАНЕ ОТНАЧАЛО"</string> <string name="workspace_cling_title" msgid="5626202359865825661">"Организиране на мястото ви"</string> <string name="workspace_cling_move_item" msgid="528201129978005352">"Докоснете и задръжте фона, за да управлявате тапета, приспособленията и настройките."</string> + <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Тапети, приспособления и настройки"</string> + <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"Докоснете и задръжте фона за персонализиране"</string> + <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"РАЗБРАХ"</string> <string name="folder_cling_title" msgid="3894908818693254164">"Ето една папка"</string> <string name="folder_cling_create_folder" msgid="6158215559475836131">"За да създадете подобна, докоснете и задръжте приложение, след което го преместете върху друго."</string> <string name="cling_dismiss" msgid="8962359497601507581">"ОK"</string> @@ -107,4 +112,14 @@ <string name="widget_button_text" msgid="2880537293434387943">"Приспособления"</string> <string name="wallpaper_button_text" msgid="8404103075899945851">"Тапети"</string> <string name="settings_button_text" msgid="8119458837558863227">"Настройки"</string> + <string name="package_state_enqueued" msgid="6227252464303085641">"Изчаква"</string> + <string name="package_state_downloading" msgid="4088770468458724721">"Изтегля се"</string> + <string name="package_state_installing" msgid="7588193972189849870">"Инсталира се"</string> + <string name="package_state_unknown" msgid="7592128424511031410">"Няма информация"</string> + <string name="package_state_error" msgid="7672093962724223588">"Не е възстановено"</string> + <string name="abandoned_clean_all" msgid="5256770727689657618">"Премахване на всички"</string> + <string name="abandoned_clean_this" msgid="7610119707847920412">"Премахване"</string> + <string name="abandoned_search" msgid="891119232568284442">"Търсене"</string> + <string name="abandoned_promises_title" msgid="7096178467971716750">"Това приложение не е инсталирано"</string> + <string name="abandoned_promise_explanation" msgid="3990027586878167529">"Приложението за тази икона не е инсталирано. Можете да я премахнете или да потърсите приложението и да го инсталирате ръчно."</string> </resources> diff --git a/res/values-bn-rBD/strings.xml b/res/values-bn-rBD/strings.xml new file mode 100644 index 000000000..f60f1c507 --- /dev/null +++ b/res/values-bn-rBD/strings.xml @@ -0,0 +1,121 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +* Copyright (C) 2008 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. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="application_name" msgid="5181331383435256801">"লঞ্চার৩"</string> + <string name="home" msgid="7658288663002113681">"হোম"</string> + <string name="uid_name" msgid="7820867637514617527">"Android প্রাথমিক অ্যাপ্লিকেশানগুলি"</string> + <string name="folder_name" msgid="7371454440695724752"></string> + <string name="activity_not_found" msgid="8071924732094499514">"অ্যাপ্লিকেশান ইনস্টল করা নেই৷"</string> + <string name="safemode_shortcut_error" msgid="9160126848219158407">"ডাউনলোড করা অ্যাপ্লিকেশান নিরাপদ মোডে অক্ষম রয়েছে"</string> + <string name="widgets_tab_label" msgid="2921133187116603919">"উইজেটগুলি"</string> + <string name="widget_adder" msgid="3201040140710381657">"উইজেটগুলি"</string> + <string name="toggle_weight_watcher" msgid="5645299835184636119">"মেম দেখান"</string> + <string name="long_press_widget_to_add" msgid="7699152356777458215">"একটি উইজেট তুলতে তা স্পর্শ করে ধরে রাখুন৷"</string> + <string name="market" msgid="2619650989819296998">"দোকান"</string> + <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string> + <string name="external_drop_widget_error" msgid="3165821058322217155">"এই হোম স্ক্রীনে আইটেম রাখা যায়নি৷"</string> + <string name="external_drop_widget_pick_title" msgid="3486317258037690630">"তৈরি করেতে উইজেট চয়ন করুন"</string> + <string name="rename_folder_label" msgid="3727762225964550653">"ফোল্ডারের নাম"</string> + <string name="rename_folder_title" msgid="3771389277707820891">"ফোল্ডার পুনঃনামকরণ করুন"</string> + <string name="rename_action" msgid="5559600076028658757">"ঠিক আছে"</string> + <string name="cancel_action" msgid="7009134900002915310">"বাতিল করুন"</string> + <string name="menu_item_add_item" msgid="1264911265836810421">"হোম স্ক্রীনে যোগ করুন"</string> + <string name="group_applications" msgid="3797214114206693605">"অ্যাপ্লিকেশানগুলি"</string> + <string name="group_shortcuts" msgid="6012256992764410535">"শর্টকাটগুলি"</string> + <string name="group_widgets" msgid="1569030723286851002">"উইজেটগুলি"</string> + <string name="completely_out_of_space" msgid="6106288382070760318">"আপনার হোম স্ক্রীনগুলিতে আর কোনো জায়গা নেই৷"</string> + <string name="out_of_space" msgid="4691004494942118364">"এই হোম স্ক্রীনে আর কোনো জায়গা নেই৷"</string> + <string name="hotseat_out_of_space" msgid="7448809638125333693">"পছন্দসই ট্রে-তে আর কোনো জায়গা নেই"</string> + <string name="invalid_hotseat_item" msgid="5779907847267573691">"পছন্দসই ট্রে\'র জন্য এই উইজেটটি খুবই বড়"</string> + <string name="shortcut_installed" msgid="1701742129426969556">"শর্টকাট \"<xliff:g id="NAME">%s</xliff:g>\" তৈরি করা হয়েছে৷"</string> + <string name="shortcut_uninstalled" msgid="8176767991305701821">"শর্টকাট \"<xliff:g id="NAME">%s</xliff:g>\" সরানো হয়েছে৷"</string> + <string name="shortcut_duplicate" msgid="9167217446062498127">"শর্টকাট <xliff:g id="NAME">%s</xliff:g> আগে থেকেই আছে৷"</string> + <string name="title_select_shortcut" msgid="6680642571148153868">"শর্টকাট চয়ন করুন"</string> + <string name="title_select_application" msgid="3280812711670683644">"অ্যাপ্লিকেশান চয়ন করুন"</string> + <string name="all_apps_button_label" msgid="9110807029020582876">"অ্যাপ্লিকেশানগুলি"</string> + <string name="all_apps_home_button_label" msgid="252062713717058851">"হোম"</string> + <string name="delete_zone_label_workspace" msgid="4009607676751398685">"সরান"</string> + <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"আনইনস্টল করুন"</string> + <string name="delete_target_label" msgid="1822697352535677073">"সরান"</string> + <string name="delete_target_uninstall_label" msgid="5100785476250872595">"আনইনস্টল করুন"</string> + <string name="info_target_label" msgid="8053346143994679532">"অ্যাপ্লিকেশানের তথ্য"</string> + <string name="accessibility_search_button" msgid="1628520399424565142">"অনুসন্ধান করুন"</string> + <string name="accessibility_voice_search_button" msgid="4637324840434406584">"ভয়েস অনুসন্ধান"</string> + <string name="accessibility_all_apps_button" msgid="2603132375383800483">"অ্যাপ্লিকেশানগুলি"</string> + <string name="accessibility_delete_button" msgid="6466114477993744621">"সরান"</string> + <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"আপডেট আনইনস্টল করুন"</string> + <string name="cab_menu_delete_app" msgid="7435191475867183689">"অ্যাপ্লিকেশান আনইনস্টল করুন"</string> + <string name="cab_menu_app_info" msgid="8593722221450362342">"অ্যাপ্লিকেশানের বিশদ বিবরণ"</string> + <string name="cab_app_selection_text" msgid="374688303047985416">"১টি অ্যাপ্লিকেশান নির্বাচন করা হয়েছে"</string> + <string name="cab_widget_selection_text" msgid="1833458597831541241">"১টি উইজেট নির্বাচন করা হয়েছে"</string> + <string name="cab_folder_selection_text" msgid="7999992513806132118">"১টি ফোল্ডার নির্বাচন করা হয়েছে"</string> + <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"১টি শর্টকাট নির্বাচন করা হয়েছে"</string> + <string name="permlab_install_shortcut" msgid="5632423390354674437">"শর্টকাটগুলি ইনস্টল করে"</string> + <string name="permdesc_install_shortcut" msgid="923466509822011139">"একটি অ্যাপ্লিকেশানকে ব্যবহারকারীর হস্তক্ষেপ ছাড়াই শর্টকাটগুলি যোগ করার অনুমতি দেয়৷"</string> + <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"শর্টকাটগুলি আনইনস্টল করে"</string> + <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"অ্যাপ্লিকেশানটিকে ব্যবহারকারীর হস্তক্ষেপ ছাড়াই শর্টকাটগুলি সরানোর অনুমতি দেয়৷"</string> + <string name="permlab_read_settings" msgid="1941457408239617576">"হোম সেটিংস এবং শর্টকাটগুলি পড়ে"</string> + <string name="permdesc_read_settings" msgid="5833423719057558387">"হোমে অ্যাপ্লিকেশানটিকে সেটিংস এবং শর্টকাটগুলি পড়তে দেয়৷"</string> + <string name="permlab_write_settings" msgid="3574213698004620587">"হোম সেটিংস এবং শর্টকাটগুলি লেখে"</string> + <string name="permdesc_write_settings" msgid="5440712911516509985">"হোমে অ্যাপ্লিকেশানটিকে সেটিংস এবং শর্টকাটগুলি পরিবর্তন করতে দেয়৷"</string> + <string name="gadget_error_text" msgid="6081085226050792095">"উইজেট লোড হতে সমস্যা হয়েছে"</string> + <string name="uninstall_system_app_text" msgid="4172046090762920660">"এটি একটি সিস্টেম অ্যাপ্লিকেশান এবং আনইনস্টল করা যাবে না৷"</string> + <string name="dream_name" msgid="1530253749244328964">"রকেট লঞ্চার"</string> + <string name="folder_hint_text" msgid="6617836969016293992">"নামবিহীন ফোল্ডার"</string> + <string name="workspace_description_format" msgid="2950174241104043327">"%1$d নম্বর হোম স্ক্রীন"</string> + <string name="default_scroll_format" msgid="7475544710230993317">"%2$dটির মধ্যে %1$dটি পৃষ্ঠা"</string> + <string name="workspace_scroll_format" msgid="8458889198184077399">"%2$dটির %1$d নম্বর হোম স্ক্রীন"</string> + <string name="apps_customize_apps_scroll_format" msgid="370005296147130238">"%2$dটির মধ্যে %1$dটি অ্যাপ্লিকেশান পৃষ্ঠা"</string> + <string name="apps_customize_widgets_scroll_format" msgid="3106209519974971521">"%2$dটির মধ্যে %1$dটি উইজেট পৃষ্ঠা"</string> + <string name="first_run_cling_title" msgid="2459738000155917941">"স্বাগতম"</string> + <string name="first_run_cling_description" msgid="6447072552696253358">"নিজের বাড়ির মতো স্বাচ্ছন্দ্য বোধ করুন৷"</string> + <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string> + <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string> + <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"অ্যাপ্লিকেশান এবং ফোল্ডারগুলির জন্য আরো স্ক্রীn তৈরি করুন"</string> + <string name="migration_cling_title" msgid="9181776667882933767">"আপনার অ্যাপ্লিকেশান আইকনগুলি অনুলিপি করুন"</string> + <string name="migration_cling_description" msgid="2752413805582227644">"আপনার পুরানো হোম স্ক্রীন থেকে আইকন এবং ফোল্ডারগুলি আমদানি করবেন?"</string> + <string name="migration_cling_copy_apps" msgid="946331230090919440">"আইকনগুলি অনুলিপি করুন"</string> + <string name="migration_cling_use_default" msgid="2626475813981258626">"নতুন করে শুরু করুন"</string> + <string name="workspace_cling_title" msgid="5626202359865825661">"আপনার স্থান সংগঠিত করুন"</string> + <string name="workspace_cling_move_item" msgid="528201129978005352">"ওয়ালপেপার, উইজেট এবং সেটিংস পরিচালনা করতে পটভূমি স্পর্শ করে ধরে রাখুন৷"</string> + <string name="folder_cling_title" msgid="3894908818693254164">"এখানে একটি ফোল্ডার আছে"</string> + <string name="folder_cling_create_folder" msgid="6158215559475836131">"এটির মতো একটি তৈরি করতে, একটি অ্যাপ্লিকেশান স্পর্শ করে ধরে রাখুন, এবং তারপরে এটিকে অন্য একটির উপরে সরিয়ে নিয়ে যান৷"</string> + <string name="cling_dismiss" msgid="8962359497601507581">"ঠিক আছে"</string> + <string name="folder_opened" msgid="94695026776264709">"ফোল্ডার খোলা হয়েছে, <xliff:g id="WIDTH">%1$d</xliff:g> বাই <xliff:g id="HEIGHT">%2$d</xliff:g>"</string> + <string name="folder_tap_to_close" msgid="1884479294466410023">"ফোল্ডার বন্ধ করতে স্পর্শ করুন"</string> + <string name="folder_tap_to_rename" msgid="9191075570492871147">"পুনঃনামকরণ সংরক্ষণ করতে স্পর্শ করুন"</string> + <string name="folder_closed" msgid="4100806530910930934">"ফোল্ডার বন্ধ করা হয়েছে"</string> + <string name="folder_renamed" msgid="1794088362165669656">"ফোল্ডারের নাম পাল্টে <xliff:g id="NAME">%1$s</xliff:g> করা হয়েছে"</string> + <string name="folder_name_format" msgid="6629239338071103179">"ফোল্ডার: <xliff:g id="NAME">%1$s</xliff:g>"</string> + <string name="widget_button_text" msgid="2880537293434387943">"উইজেটগুলি"</string> + <string name="wallpaper_button_text" msgid="8404103075899945851">"ওয়ালপেপারগুলি"</string> + <string name="settings_button_text" msgid="8119458837558863227">"সেটিংস"</string> + <string name="package_state_enqueued" msgid="6227252464303085641">"প্রতীক্ষা"</string> + <string name="package_state_downloading" msgid="4088770468458724721">"ডাউনলোড হচ্ছে"</string> + <string name="package_state_installing" msgid="7588193972189849870">"ইনস্টল করা হচ্ছে"</string> + <string name="package_state_unknown" msgid="7592128424511031410">"অজানা"</string> + <string name="package_state_error" msgid="7672093962724223588">"পুনঃস্থাপন করা যায়নি"</string> + <string name="abandoned_clean_all" msgid="5256770727689657618">"সবগুলি সরান"</string> + <string name="abandoned_clean_this" msgid="7610119707847920412">"সরান"</string> + <string name="abandoned_search" msgid="891119232568284442">"অনুসন্ধান"</string> + <string name="abandoned_promises_title" msgid="7096178467971716750">"এই অ্যাপ্লিকেশানটি ইন্সটল করা নাই"</string> + <string name="abandoned_promise_explanation" msgid="3990027586878167529">"এই আইকনের অ্যাপ্লিকেশানটি ইন্সটল করা নাই। আপনি এটি সরাতে পারেন বা অ্যাপ্লিকেশানটি অনুসন্ধান করে এটি নিজে ইন্সটল করতে পারেন।"</string> +</resources> diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml index 3e6bedba9..6d1023545 100644 --- a/res/values-ca/strings.xml +++ b/res/values-ca/strings.xml @@ -24,6 +24,7 @@ <string name="uid_name" msgid="7820867637514617527">"Aplicacions principals d\'Android"</string> <string name="folder_name" msgid="7371454440695724752"></string> <string name="activity_not_found" msgid="8071924732094499514">"L\'aplicació no s\'ha instal·lat."</string> + <string name="safemode_shortcut_error" msgid="9160126848219158407">"L\'aplicació que has baixat està desactivada al mode segur."</string> <string name="widgets_tab_label" msgid="2921133187116603919">"Widgets"</string> <string name="widget_adder" msgid="3201040140710381657">"Widgets"</string> <string name="toggle_weight_watcher" msgid="5645299835184636119">"Mostra la memòria"</string> @@ -76,6 +77,7 @@ <string name="permlab_write_settings" msgid="3574213698004620587">"escriu la configuració i les dreceres de la pantalla d\'inici"</string> <string name="permdesc_write_settings" msgid="5440712911516509985">"Permet que l\'aplicació canviï la configuració i les dreceres de la pantalla d\'inici."</string> <string name="gadget_error_text" msgid="6081085226050792095">"S\'ha produït un problema en carregar el widget"</string> + <string name="gadget_setup_text" msgid="8274003207686040488">"Configuració"</string> <string name="uninstall_system_app_text" msgid="4172046090762920660">"Aquesta aplicació és una aplicació del sistema i no es pot desinstal·lar."</string> <string name="dream_name" msgid="1530253749244328964">"Rocket Launcher"</string> <string name="folder_hint_text" msgid="6617836969016293992">"Carpeta sense nom"</string> @@ -95,6 +97,9 @@ <string name="migration_cling_use_default" msgid="2626475813981258626">"NOU COMENÇAMENT"</string> <string name="workspace_cling_title" msgid="5626202359865825661">"Organitza el teu espai"</string> <string name="workspace_cling_move_item" msgid="528201129978005352">"Toca i mantén premut el fons per gestionar el fons de pantalla, els widgets i la configuració."</string> + <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Fons de pantalla, widgets i configuració"</string> + <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"Mantén premut el fons per fer personalitzacions."</string> + <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"D\'ACORD"</string> <string name="folder_cling_title" msgid="3894908818693254164">"Aquí hi ha una carpeta"</string> <string name="folder_cling_create_folder" msgid="6158215559475836131">"Per crear-ne una com aquesta, mantén premuda una aplicació i, a continuació, mou-la sobre una altra."</string> <string name="cling_dismiss" msgid="8962359497601507581">"D\'acord"</string> @@ -107,4 +112,14 @@ <string name="widget_button_text" msgid="2880537293434387943">"Widgets"</string> <string name="wallpaper_button_text" msgid="8404103075899945851">"Fons de pantalla"</string> <string name="settings_button_text" msgid="8119458837558863227">"Configuració"</string> + <string name="package_state_enqueued" msgid="6227252464303085641">"En espera"</string> + <string name="package_state_downloading" msgid="4088770468458724721">"S\'està baixant"</string> + <string name="package_state_installing" msgid="7588193972189849870">"Instal·lant"</string> + <string name="package_state_unknown" msgid="7592128424511031410">"Desconegut"</string> + <string name="package_state_error" msgid="7672093962724223588">"No restaurat"</string> + <string name="abandoned_clean_all" msgid="5256770727689657618">"Suprimeix-ho tot"</string> + <string name="abandoned_clean_this" msgid="7610119707847920412">"Suprimeix"</string> + <string name="abandoned_search" msgid="891119232568284442">"Cerca"</string> + <string name="abandoned_promises_title" msgid="7096178467971716750">"Aquesta aplicació no està instal·lada"</string> + <string name="abandoned_promise_explanation" msgid="3990027586878167529">"L\'aplicació d\'aquesta icona no està instal·lada. Pots suprimir-la o cercar l\'aplicació i instal·lar-la manualment."</string> </resources> diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml index 3a0e6721c..f729a460e 100644 --- a/res/values-cs/strings.xml +++ b/res/values-cs/strings.xml @@ -24,6 +24,7 @@ <string name="uid_name" msgid="7820867637514617527">"Android Core Apps"</string> <string name="folder_name" msgid="7371454440695724752"></string> <string name="activity_not_found" msgid="8071924732094499514">"Aplikace není nainstalována."</string> + <string name="safemode_shortcut_error" msgid="9160126848219158407">"Stažená aplikace je v nouzovém režimu zakázána"</string> <string name="widgets_tab_label" msgid="2921133187116603919">"Widgety"</string> <string name="widget_adder" msgid="3201040140710381657">"Widgety"</string> <string name="toggle_weight_watcher" msgid="5645299835184636119">"Zobrazit Mem"</string> @@ -76,6 +77,7 @@ <string name="permlab_write_settings" msgid="3574213698004620587">"zápis nastavení a odkazů plochy"</string> <string name="permdesc_write_settings" msgid="5440712911516509985">"Umožňuje aplikaci změnit nastavení a odkazy na ploše."</string> <string name="gadget_error_text" msgid="6081085226050792095">"Problém s načtením widgetu"</string> + <string name="gadget_setup_text" msgid="8274003207686040488">"Nastavení"</string> <string name="uninstall_system_app_text" msgid="4172046090762920660">"Toto je systémová aplikace a nelze ji odinstalovat."</string> <string name="dream_name" msgid="1530253749244328964">"Rocket Launcher"</string> <string name="folder_hint_text" msgid="6617836969016293992">"Složka bez názvu"</string> @@ -95,6 +97,9 @@ <string name="migration_cling_use_default" msgid="2626475813981258626">"ZAČÍT S VÝCHOZÍM ROZVRŽENÍM"</string> <string name="workspace_cling_title" msgid="5626202359865825661">"Organizace prostoru"</string> <string name="workspace_cling_move_item" msgid="528201129978005352">"Chcete-li spravovat tapetu, widgety a nastavení, dotkněte se pozadí a přidržte je."</string> + <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Tapety, widgety a nastavení"</string> + <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"Pozadí můžete přizpůsobit klepnutím a podržením"</string> + <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"ROZUMÍM"</string> <string name="folder_cling_title" msgid="3894908818693254164">"Toto je složka"</string> <string name="folder_cling_create_folder" msgid="6158215559475836131">"Chcete-li vytvořit složku, přetáhněte aplikaci na jinou aplikaci."</string> <string name="cling_dismiss" msgid="8962359497601507581">"OK"</string> @@ -107,4 +112,14 @@ <string name="widget_button_text" msgid="2880537293434387943">"Widgety"</string> <string name="wallpaper_button_text" msgid="8404103075899945851">"Tapety"</string> <string name="settings_button_text" msgid="8119458837558863227">"Nastavení"</string> + <string name="package_state_enqueued" msgid="6227252464303085641">"Čekání"</string> + <string name="package_state_downloading" msgid="4088770468458724721">"Stahování"</string> + <string name="package_state_installing" msgid="7588193972189849870">"Instalace"</string> + <string name="package_state_unknown" msgid="7592128424511031410">"Neznámé"</string> + <string name="package_state_error" msgid="7672093962724223588">"Nebylo obnoveno"</string> + <string name="abandoned_clean_all" msgid="5256770727689657618">"Odstranit vše"</string> + <string name="abandoned_clean_this" msgid="7610119707847920412">"Odstranit"</string> + <string name="abandoned_search" msgid="891119232568284442">"Hledat"</string> + <string name="abandoned_promises_title" msgid="7096178467971716750">"Tato aplikace není nainstalována"</string> + <string name="abandoned_promise_explanation" msgid="3990027586878167529">"Aplikace pro tuto ikonu není nainstalována. Můžete ikonu odstranit nebo zkusit aplikaci vyhledat a nainstalovat ručně."</string> </resources> diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml index eabde3e2b..85159b2e1 100644 --- a/res/values-da/strings.xml +++ b/res/values-da/strings.xml @@ -24,6 +24,7 @@ <string name="uid_name" msgid="7820867637514617527">"Kerneapps i Android"</string> <string name="folder_name" msgid="7371454440695724752"></string> <string name="activity_not_found" msgid="8071924732094499514">"Appen er ikke installeret."</string> + <string name="safemode_shortcut_error" msgid="9160126848219158407">"Downloadet app er deaktiveret i sikker tilstand"</string> <string name="widgets_tab_label" msgid="2921133187116603919">"Widgets"</string> <string name="widget_adder" msgid="3201040140710381657">"Widgets"</string> <string name="toggle_weight_watcher" msgid="5645299835184636119">"Vis Mem"</string> @@ -76,6 +77,7 @@ <string name="permlab_write_settings" msgid="3574213698004620587">"skrive indstillinger og genveje for startskærmen"</string> <string name="permdesc_write_settings" msgid="5440712911516509985">"Tillader, at appen ændrer indstillingerne og genvejene på startskærmen."</string> <string name="gadget_error_text" msgid="6081085226050792095">"Der er problemer med indlæsning af widgetten"</string> + <string name="gadget_setup_text" msgid="8274003207686040488">"Konfigurer"</string> <string name="uninstall_system_app_text" msgid="4172046090762920660">"Dette er en systemapp, som ikke kan afinstalleres."</string> <string name="dream_name" msgid="1530253749244328964">"Rocket Launcher"</string> <string name="folder_hint_text" msgid="6617836969016293992">"Unavngiven mappe"</string> @@ -95,6 +97,9 @@ <string name="migration_cling_use_default" msgid="2626475813981258626">"START PÅ EN FRISK"</string> <string name="workspace_cling_title" msgid="5626202359865825661">"Organiser din arbejdsplads"</string> <string name="workspace_cling_move_item" msgid="528201129978005352">"Tryk på en baggrund, og hold fingeren nede for at administrere baggrunde, widgets og indstillinger."</string> + <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Baggrunde, widgets og indstillinger"</string> + <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"Tryk på baggrunden, og hold fingeren nede for at tilpasse den"</string> + <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"OK, FORSTÅET"</string> <string name="folder_cling_title" msgid="3894908818693254164">"Her kan du se en mappe"</string> <string name="folder_cling_create_folder" msgid="6158215559475836131">"Du kan oprette en mappe magen til denne ved at trykke på en app og holde fingeren nede, mens du flytter appen til en anden mappe."</string> <string name="cling_dismiss" msgid="8962359497601507581">"OK"</string> @@ -107,4 +112,14 @@ <string name="widget_button_text" msgid="2880537293434387943">"Widgets"</string> <string name="wallpaper_button_text" msgid="8404103075899945851">"Baggrunde"</string> <string name="settings_button_text" msgid="8119458837558863227">"Indstillinger"</string> + <string name="package_state_enqueued" msgid="6227252464303085641">"Afventer"</string> + <string name="package_state_downloading" msgid="4088770468458724721">"Downloader"</string> + <string name="package_state_installing" msgid="7588193972189849870">"Installerer"</string> + <string name="package_state_unknown" msgid="7592128424511031410">"Ukendt"</string> + <string name="package_state_error" msgid="7672093962724223588">"Ikke gendannet"</string> + <string name="abandoned_clean_all" msgid="5256770727689657618">"Slet alle"</string> + <string name="abandoned_clean_this" msgid="7610119707847920412">"Fjern"</string> + <string name="abandoned_search" msgid="891119232568284442">"Søg"</string> + <string name="abandoned_promises_title" msgid="7096178467971716750">"Denne app er ikke installeret"</string> + <string name="abandoned_promise_explanation" msgid="3990027586878167529">"Appen, der hører til dette ikon, er ikke installeret. Du kan fjerne den eller prøve at søge efter appen og installere den manuelt."</string> </resources> diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml index 27ad73ada..698a25413 100644 --- a/res/values-de/strings.xml +++ b/res/values-de/strings.xml @@ -24,6 +24,7 @@ <string name="uid_name" msgid="7820867637514617527">"Android Core Apps"</string> <string name="folder_name" msgid="7371454440695724752"></string> <string name="activity_not_found" msgid="8071924732094499514">"App ist nicht installiert."</string> + <string name="safemode_shortcut_error" msgid="9160126848219158407">"Heruntergeladene App im abgesicherten Modus deaktiviert"</string> <string name="widgets_tab_label" msgid="2921133187116603919">"Widgets"</string> <string name="widget_adder" msgid="3201040140710381657">"Widgets"</string> <string name="toggle_weight_watcher" msgid="5645299835184636119">"Speicher anzeigen"</string> @@ -76,6 +77,7 @@ <string name="permlab_write_settings" msgid="3574213698004620587">"Einstellungen und Verknüpfungen für den Startbildschirm schreiben"</string> <string name="permdesc_write_settings" msgid="5440712911516509985">"Ermöglicht der App, die Einstellungen und Verknüpfungen auf dem Startbildschirm zu ändern"</string> <string name="gadget_error_text" msgid="6081085226050792095">"Problem beim Laden des Widgets"</string> + <string name="gadget_setup_text" msgid="8274003207686040488">"Einrichten"</string> <string name="uninstall_system_app_text" msgid="4172046090762920660">"Dies ist eine Systemanwendung, die nicht deinstalliert werden kann."</string> <string name="dream_name" msgid="1530253749244328964">"Rocket Launcher"</string> <string name="folder_hint_text" msgid="6617836969016293992">"Unbenannter Ordner"</string> @@ -95,6 +97,9 @@ <string name="migration_cling_use_default" msgid="2626475813981258626">"Standardübersicht verwenden"</string> <string name="workspace_cling_title" msgid="5626202359865825661">"Arbeitsbereich organisieren"</string> <string name="workspace_cling_move_item" msgid="528201129978005352">"Hintergrund berühren und halten, um Hintergrund, Widgets und Einstellungen zu verwalten"</string> + <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Hintergründe, Widgets & Einstellungen"</string> + <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"Berühren und halten Sie den Hintergrund, um ihn anzupassen."</string> + <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"OK"</string> <string name="folder_cling_title" msgid="3894908818693254164">"Hier ist ein Ordner"</string> <string name="folder_cling_create_folder" msgid="6158215559475836131">"Um einen Ordner zu erstellen, berühren und halten Sie eine App und verschieben Sie sie auf eine andere."</string> <string name="cling_dismiss" msgid="8962359497601507581">"OK"</string> @@ -107,4 +112,14 @@ <string name="widget_button_text" msgid="2880537293434387943">"Widgets"</string> <string name="wallpaper_button_text" msgid="8404103075899945851">"Hintergründe"</string> <string name="settings_button_text" msgid="8119458837558863227">"Einstellungen"</string> + <string name="package_state_enqueued" msgid="6227252464303085641">"Warten"</string> + <string name="package_state_downloading" msgid="4088770468458724721">"Download läuft"</string> + <string name="package_state_installing" msgid="7588193972189849870">"Installation"</string> + <string name="package_state_unknown" msgid="7592128424511031410">"Unbekannt"</string> + <string name="package_state_error" msgid="7672093962724223588">"Nicht wiederhergestellt"</string> + <string name="abandoned_clean_all" msgid="5256770727689657618">"Alle entfernen"</string> + <string name="abandoned_clean_this" msgid="7610119707847920412">"Entfernen"</string> + <string name="abandoned_search" msgid="891119232568284442">"Suchen"</string> + <string name="abandoned_promises_title" msgid="7096178467971716750">"Diese App ist nicht installiert"</string> + <string name="abandoned_promise_explanation" msgid="3990027586878167529">"Die App für dieses Symbol ist nicht installiert. Sie können das Symbol entfernen oder nach der App suchen und sie manuell installieren."</string> </resources> diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml index ec05ae57c..3eec27d4f 100644 --- a/res/values-el/strings.xml +++ b/res/values-el/strings.xml @@ -24,6 +24,7 @@ <string name="uid_name" msgid="7820867637514617527">"Βασικές εφαρμογές Android"</string> <string name="folder_name" msgid="7371454440695724752"></string> <string name="activity_not_found" msgid="8071924732094499514">"Η εφαρμογή δεν έχει εγκατασταθεί."</string> + <string name="safemode_shortcut_error" msgid="9160126848219158407">"Η λήψη εφαρμογών απενεργοποήθηκε στην Ασφαλή λειτουργία"</string> <string name="widgets_tab_label" msgid="2921133187116603919">"Γραφικά στοιχεία"</string> <string name="widget_adder" msgid="3201040140710381657">"Γραφικά στοιχεία"</string> <string name="toggle_weight_watcher" msgid="5645299835184636119">"Εμφάνιση Mem"</string> @@ -76,6 +77,7 @@ <string name="permlab_write_settings" msgid="3574213698004620587">"εγγραφή ρυθμίσεων και συντομεύσεων αρχικής οθόνης"</string> <string name="permdesc_write_settings" msgid="5440712911516509985">"Επιτρέπει στην εφαρμογή την αλλαγή των ρυθμίσεων και των συντομεύσεων στην Αρχική οθόνη."</string> <string name="gadget_error_text" msgid="6081085226050792095">"Παρουσιάστηκε πρόβλημα στη φόρτωση του γραφικού στοιχείου"</string> + <string name="gadget_setup_text" msgid="8274003207686040488">"Ρύθμιση"</string> <string name="uninstall_system_app_text" msgid="4172046090762920660">"Αυτή είναι μια εφαρμογή συστήματος και δεν είναι δυνατή η κατάργηση της εγκατάστασής της."</string> <string name="dream_name" msgid="1530253749244328964">"Rocket Launcher"</string> <string name="folder_hint_text" msgid="6617836969016293992">"Φάκελος χωρίς όνομα"</string> @@ -95,6 +97,9 @@ <string name="migration_cling_use_default" msgid="2626475813981258626">"ΝΕΑ ΕΝΑΡΞΗ"</string> <string name="workspace_cling_title" msgid="5626202359865825661">"Οργανώστε το χώρο σας"</string> <string name="workspace_cling_move_item" msgid="528201129978005352">"Αγγίξτε παρατεταμένα το φόντο για να διαχειριστείτε την ταπετσαρία, τα γραφικά στοιχεία και τις ρυθμίσεις."</string> + <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Ταπετσαρίες, γραφικά στοιχεία και ρυθμίσεις"</string> + <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"Αγγίξτε παρατεταμένα το παρασκήνιο για προσαρμογή"</string> + <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"ΕΓΙΝΕ"</string> <string name="folder_cling_title" msgid="3894908818693254164">"Ορίστε ένας φάκελος"</string> <string name="folder_cling_create_folder" msgid="6158215559475836131">"Για να δημιουργήσετε έναν φάκελο σαν κι αυτόν, πατήστε παρατεταμένα μια εφαρμογή και στη συνέχεια, μετακινήστε τη πάνω σε μια άλλη."</string> <string name="cling_dismiss" msgid="8962359497601507581">"OK"</string> @@ -107,4 +112,14 @@ <string name="widget_button_text" msgid="2880537293434387943">"Γραφικά στοιχεία"</string> <string name="wallpaper_button_text" msgid="8404103075899945851">"Ταπετσαρίες"</string> <string name="settings_button_text" msgid="8119458837558863227">"Ρυθμίσεις"</string> + <string name="package_state_enqueued" msgid="6227252464303085641">"Αναμονή"</string> + <string name="package_state_downloading" msgid="4088770468458724721">"Λήψη "</string> + <string name="package_state_installing" msgid="7588193972189849870">"Εγκατάσταση"</string> + <string name="package_state_unknown" msgid="7592128424511031410">"Άγνωστο"</string> + <string name="package_state_error" msgid="7672093962724223588">"Δεν ανακτήθηκε"</string> + <string name="abandoned_clean_all" msgid="5256770727689657618">"Κατάργηση όλων"</string> + <string name="abandoned_clean_this" msgid="7610119707847920412">"Κατάργηση"</string> + <string name="abandoned_search" msgid="891119232568284442">"Αναζήτηση"</string> + <string name="abandoned_promises_title" msgid="7096178467971716750">"Αυτή η εφαρμογή δεν είναι εγκατεστημένη"</string> + <string name="abandoned_promise_explanation" msgid="3990027586878167529">"Η εφαρμογή γι\' αυτό το εικονίδιο δεν είναι εγκατεστημένη. Μπορείτε να το καταργήσετε ή να αναζητήσετε την εφαρμογή και να την εγκαταστήσετε με μη αυτόματο τρόπο."</string> </resources> diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml index cab17077a..615e5c90d 100644 --- a/res/values-en-rGB/strings.xml +++ b/res/values-en-rGB/strings.xml @@ -24,6 +24,7 @@ <string name="uid_name" msgid="7820867637514617527">"Android Core Apps"</string> <string name="folder_name" msgid="7371454440695724752"></string> <string name="activity_not_found" msgid="8071924732094499514">"App isn\'t installed."</string> + <string name="safemode_shortcut_error" msgid="9160126848219158407">"Downloaded app disabled in Safe mode"</string> <string name="widgets_tab_label" msgid="2921133187116603919">"Widgets"</string> <string name="widget_adder" msgid="3201040140710381657">"Widgets"</string> <string name="toggle_weight_watcher" msgid="5645299835184636119">"Show Mem"</string> @@ -76,6 +77,7 @@ <string name="permlab_write_settings" msgid="3574213698004620587">"write Home settings and shortcuts"</string> <string name="permdesc_write_settings" msgid="5440712911516509985">"Allows the app to change the settings and shortcuts in Home."</string> <string name="gadget_error_text" msgid="6081085226050792095">"Problem loading widget"</string> + <string name="gadget_setup_text" msgid="8274003207686040488">"Setup"</string> <string name="uninstall_system_app_text" msgid="4172046090762920660">"This is a system app and can\'t be uninstalled."</string> <string name="dream_name" msgid="1530253749244328964">"Rocket Launcher"</string> <string name="folder_hint_text" msgid="6617836969016293992">"Unnamed Folder"</string> @@ -95,6 +97,9 @@ <string name="migration_cling_use_default" msgid="2626475813981258626">"START AFRESH"</string> <string name="workspace_cling_title" msgid="5626202359865825661">"Organise your space"</string> <string name="workspace_cling_move_item" msgid="528201129978005352">"Touch & hold background to manage wallpaper, widgets and settings."</string> + <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Wallpapers, widgets, & settings"</string> + <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"Touch & hold background to customise"</string> + <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"GOT IT"</string> <string name="folder_cling_title" msgid="3894908818693254164">"Here\'s a folder"</string> <string name="folder_cling_create_folder" msgid="6158215559475836131">"To create one like this, touch & hold an app, then move it over another."</string> <string name="cling_dismiss" msgid="8962359497601507581">"OK"</string> @@ -107,4 +112,14 @@ <string name="widget_button_text" msgid="2880537293434387943">"Widgets"</string> <string name="wallpaper_button_text" msgid="8404103075899945851">"Wallpapers"</string> <string name="settings_button_text" msgid="8119458837558863227">"Settings"</string> + <string name="package_state_enqueued" msgid="6227252464303085641">"Waiting"</string> + <string name="package_state_downloading" msgid="4088770468458724721">"Downloading"</string> + <string name="package_state_installing" msgid="7588193972189849870">"Installing"</string> + <string name="package_state_unknown" msgid="7592128424511031410">"Unknown"</string> + <string name="package_state_error" msgid="7672093962724223588">"Not restored"</string> + <string name="abandoned_clean_all" msgid="5256770727689657618">"Remove All"</string> + <string name="abandoned_clean_this" msgid="7610119707847920412">"Remove"</string> + <string name="abandoned_search" msgid="891119232568284442">"Search"</string> + <string name="abandoned_promises_title" msgid="7096178467971716750">"This app is not installed"</string> + <string name="abandoned_promise_explanation" msgid="3990027586878167529">"The app for this icon isn\'t installed. You can remove it, or search for the app and install it manually."</string> </resources> diff --git a/res/values-en-rIN/strings.xml b/res/values-en-rIN/strings.xml index cab17077a..615e5c90d 100644 --- a/res/values-en-rIN/strings.xml +++ b/res/values-en-rIN/strings.xml @@ -24,6 +24,7 @@ <string name="uid_name" msgid="7820867637514617527">"Android Core Apps"</string> <string name="folder_name" msgid="7371454440695724752"></string> <string name="activity_not_found" msgid="8071924732094499514">"App isn\'t installed."</string> + <string name="safemode_shortcut_error" msgid="9160126848219158407">"Downloaded app disabled in Safe mode"</string> <string name="widgets_tab_label" msgid="2921133187116603919">"Widgets"</string> <string name="widget_adder" msgid="3201040140710381657">"Widgets"</string> <string name="toggle_weight_watcher" msgid="5645299835184636119">"Show Mem"</string> @@ -76,6 +77,7 @@ <string name="permlab_write_settings" msgid="3574213698004620587">"write Home settings and shortcuts"</string> <string name="permdesc_write_settings" msgid="5440712911516509985">"Allows the app to change the settings and shortcuts in Home."</string> <string name="gadget_error_text" msgid="6081085226050792095">"Problem loading widget"</string> + <string name="gadget_setup_text" msgid="8274003207686040488">"Setup"</string> <string name="uninstall_system_app_text" msgid="4172046090762920660">"This is a system app and can\'t be uninstalled."</string> <string name="dream_name" msgid="1530253749244328964">"Rocket Launcher"</string> <string name="folder_hint_text" msgid="6617836969016293992">"Unnamed Folder"</string> @@ -95,6 +97,9 @@ <string name="migration_cling_use_default" msgid="2626475813981258626">"START AFRESH"</string> <string name="workspace_cling_title" msgid="5626202359865825661">"Organise your space"</string> <string name="workspace_cling_move_item" msgid="528201129978005352">"Touch & hold background to manage wallpaper, widgets and settings."</string> + <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Wallpapers, widgets, & settings"</string> + <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"Touch & hold background to customise"</string> + <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"GOT IT"</string> <string name="folder_cling_title" msgid="3894908818693254164">"Here\'s a folder"</string> <string name="folder_cling_create_folder" msgid="6158215559475836131">"To create one like this, touch & hold an app, then move it over another."</string> <string name="cling_dismiss" msgid="8962359497601507581">"OK"</string> @@ -107,4 +112,14 @@ <string name="widget_button_text" msgid="2880537293434387943">"Widgets"</string> <string name="wallpaper_button_text" msgid="8404103075899945851">"Wallpapers"</string> <string name="settings_button_text" msgid="8119458837558863227">"Settings"</string> + <string name="package_state_enqueued" msgid="6227252464303085641">"Waiting"</string> + <string name="package_state_downloading" msgid="4088770468458724721">"Downloading"</string> + <string name="package_state_installing" msgid="7588193972189849870">"Installing"</string> + <string name="package_state_unknown" msgid="7592128424511031410">"Unknown"</string> + <string name="package_state_error" msgid="7672093962724223588">"Not restored"</string> + <string name="abandoned_clean_all" msgid="5256770727689657618">"Remove All"</string> + <string name="abandoned_clean_this" msgid="7610119707847920412">"Remove"</string> + <string name="abandoned_search" msgid="891119232568284442">"Search"</string> + <string name="abandoned_promises_title" msgid="7096178467971716750">"This app is not installed"</string> + <string name="abandoned_promise_explanation" msgid="3990027586878167529">"The app for this icon isn\'t installed. You can remove it, or search for the app and install it manually."</string> </resources> diff --git a/res/values-en/dimens.xml b/res/values-en/dimens.xml deleted file mode 100644 index 01d4693c7..000000000 --- a/res/values-en/dimens.xml +++ /dev/null @@ -1,24 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2009 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. ---> - -<resources> -<!-- Cling --> - <dimen name="cling_title_text_size">22sp</dimen> - <dimen name="cling_text_size">16sp</dimen> - <dimen name="cling_alt_title_text_size">30sp</dimen> - <dimen name="cling_alt_text_size">16sp</dimen> - <dimen name="cling_hint_text_size">18sp</dimen> -</resources> diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml index 278f0d82f..31afa3e52 100644 --- a/res/values-es-rUS/strings.xml +++ b/res/values-es-rUS/strings.xml @@ -24,6 +24,7 @@ <string name="uid_name" msgid="7820867637514617527">"Aplicaciones básicas de Android"</string> <string name="folder_name" msgid="7371454440695724752"></string> <string name="activity_not_found" msgid="8071924732094499514">"No se instaló la aplicación."</string> + <string name="safemode_shortcut_error" msgid="9160126848219158407">"Aplicación descargada inhabilitada en modo seguro"</string> <string name="widgets_tab_label" msgid="2921133187116603919">"Widgets"</string> <string name="widget_adder" msgid="3201040140710381657">"Widgets"</string> <string name="toggle_weight_watcher" msgid="5645299835184636119">"Mostrar memoria"</string> @@ -76,6 +77,7 @@ <string name="permlab_write_settings" msgid="3574213698004620587">"escribir configuración y accesos directos de la pantalla principal"</string> <string name="permdesc_write_settings" msgid="5440712911516509985">"Permite que la aplicación cambie la configuración y los accesos directos de la pantalla principal."</string> <string name="gadget_error_text" msgid="6081085226050792095">"Problema al cargar el widget"</string> + <string name="gadget_setup_text" msgid="8274003207686040488">"Configuración"</string> <string name="uninstall_system_app_text" msgid="4172046090762920660">"Esta es una aplicación del sistema y no se puede desinstalar."</string> <string name="dream_name" msgid="1530253749244328964">"Lanzacohetes"</string> <string name="folder_hint_text" msgid="6617836969016293992">"Carpeta sin nombre"</string> @@ -95,6 +97,9 @@ <string name="migration_cling_use_default" msgid="2626475813981258626">"EMPEZAR DE CERO"</string> <string name="workspace_cling_title" msgid="5626202359865825661">"Organiza tu espacio"</string> <string name="workspace_cling_move_item" msgid="528201129978005352">"Mantén presionado el fondo para administrar el fondo de pantalla, los widgets y la configuración."</string> + <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Fondos, widgets y configuración"</string> + <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"Mantén presionado el fondo para personalizarlo"</string> + <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"ENTENDIDO"</string> <string name="folder_cling_title" msgid="3894908818693254164">"Aquí tienes una carpeta"</string> <string name="folder_cling_create_folder" msgid="6158215559475836131">"Para crear una carpeta como esta, mantén presionada una aplicación y luego muévela sobre otra."</string> <string name="cling_dismiss" msgid="8962359497601507581">"Aceptar"</string> @@ -107,4 +112,14 @@ <string name="widget_button_text" msgid="2880537293434387943">"Widgets"</string> <string name="wallpaper_button_text" msgid="8404103075899945851">"Fondos de pantalla"</string> <string name="settings_button_text" msgid="8119458837558863227">"Configuración"</string> + <string name="package_state_enqueued" msgid="6227252464303085641">"Pendiente"</string> + <string name="package_state_downloading" msgid="4088770468458724721">"Descargando"</string> + <string name="package_state_installing" msgid="7588193972189849870">"Instalando"</string> + <string name="package_state_unknown" msgid="7592128424511031410">"Desconocido"</string> + <string name="package_state_error" msgid="7672093962724223588">"No restaurado"</string> + <string name="abandoned_clean_all" msgid="5256770727689657618">"Eliminar todo"</string> + <string name="abandoned_clean_this" msgid="7610119707847920412">"Eliminar"</string> + <string name="abandoned_search" msgid="891119232568284442">"Buscar"</string> + <string name="abandoned_promises_title" msgid="7096178467971716750">"Esta aplicación no está instalada"</string> + <string name="abandoned_promise_explanation" msgid="3990027586878167529">"La aplicación para este ícono no está instalada. Puedes eliminar el ícono o buscar la aplicación e instarla manualmente."</string> </resources> diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml index f9cf809b2..4e9141208 100644 --- a/res/values-es/strings.xml +++ b/res/values-es/strings.xml @@ -24,6 +24,7 @@ <string name="uid_name" msgid="7820867637514617527">"Aplicaciones básicas de Android"</string> <string name="folder_name" msgid="7371454440695724752"></string> <string name="activity_not_found" msgid="8071924732094499514">"La aplicación no está instalada."</string> + <string name="safemode_shortcut_error" msgid="9160126848219158407">"Aplicación descargada inhabilitada en modo seguro"</string> <string name="widgets_tab_label" msgid="2921133187116603919">"Widgets"</string> <string name="widget_adder" msgid="3201040140710381657">"Widgets"</string> <string name="toggle_weight_watcher" msgid="5645299835184636119">"Mostrar memoria"</string> @@ -76,6 +77,7 @@ <string name="permlab_write_settings" msgid="3574213698004620587">"escribir información de accesos directos y de ajustes de la pantalla de inicio"</string> <string name="permdesc_write_settings" msgid="5440712911516509985">"Permite que las aplicaciones cambien los ajustes y los accesos directos de la pantalla de inicio."</string> <string name="gadget_error_text" msgid="6081085226050792095">"Problema al cargar el widget"</string> + <string name="gadget_setup_text" msgid="8274003207686040488">"Configuración"</string> <string name="uninstall_system_app_text" msgid="4172046090762920660">"Esta aplicación es del sistema y no se puede desinstalar."</string> <string name="dream_name" msgid="1530253749244328964">"Rocket Launcher"</string> <string name="folder_hint_text" msgid="6617836969016293992">"Carpeta sin nombre"</string> @@ -95,6 +97,9 @@ <string name="migration_cling_use_default" msgid="2626475813981258626">"AJUSTES PREDETERMINADOS"</string> <string name="workspace_cling_title" msgid="5626202359865825661">"Organiza tu espacio"</string> <string name="workspace_cling_move_item" msgid="528201129978005352">"Mantén pulsado el fondo para gestionar el fondo de pantalla, los widgets y los ajustes."</string> + <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Fondos de pantalla, widgets y ajustes"</string> + <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"Mantén pulsado el fondo para personalizarlo"</string> + <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"ENTENDIDO"</string> <string name="folder_cling_title" msgid="3894908818693254164">"Esto es una carpeta"</string> <string name="folder_cling_create_folder" msgid="6158215559475836131">"Para crear una carpeta como esta, mantén pulsada una aplicación y muévela sobre otra."</string> <string name="cling_dismiss" msgid="8962359497601507581">"Aceptar"</string> @@ -107,4 +112,14 @@ <string name="widget_button_text" msgid="2880537293434387943">"Widgets"</string> <string name="wallpaper_button_text" msgid="8404103075899945851">"Fondos de pantalla"</string> <string name="settings_button_text" msgid="8119458837558863227">"Ajustes"</string> + <string name="package_state_enqueued" msgid="6227252464303085641">"Esperando"</string> + <string name="package_state_downloading" msgid="4088770468458724721">"Descargando"</string> + <string name="package_state_installing" msgid="7588193972189849870">"Instalando"</string> + <string name="package_state_unknown" msgid="7592128424511031410">"Desconocido"</string> + <string name="package_state_error" msgid="7672093962724223588">"No restaurado"</string> + <string name="abandoned_clean_all" msgid="5256770727689657618">"Eliminar todo"</string> + <string name="abandoned_clean_this" msgid="7610119707847920412">"Eliminar"</string> + <string name="abandoned_search" msgid="891119232568284442">"Buscar"</string> + <string name="abandoned_promises_title" msgid="7096178467971716750">"Esta aplicación no está instalada"</string> + <string name="abandoned_promise_explanation" msgid="3990027586878167529">"La aplicación de este icono no está instalada. Puedes eliminar el icono o buscar la aplicación e instalarla manualmente."</string> </resources> diff --git a/res/values-et-rEE/strings.xml b/res/values-et-rEE/strings.xml index 92985d229..fa352a1a3 100644 --- a/res/values-et-rEE/strings.xml +++ b/res/values-et-rEE/strings.xml @@ -24,6 +24,7 @@ <string name="uid_name" msgid="7820867637514617527">"Androidi tuumrakendused"</string> <string name="folder_name" msgid="7371454440695724752"></string> <string name="activity_not_found" msgid="8071924732094499514">"Rakendus pole installitud."</string> + <string name="safemode_shortcut_error" msgid="9160126848219158407">"Allalaetud rakendus on turvarežiimis keelatud"</string> <string name="widgets_tab_label" msgid="2921133187116603919">"Vidinad"</string> <string name="widget_adder" msgid="3201040140710381657">"Vidinad"</string> <string name="toggle_weight_watcher" msgid="5645299835184636119">"Mälu kuvamine"</string> @@ -76,6 +77,7 @@ <string name="permlab_write_settings" msgid="3574213698004620587">"kirjuta avaekraani seaded ja otseteed"</string> <string name="permdesc_write_settings" msgid="5440712911516509985">"Võimaldab rakendusel muuta avaekraanil seadeid ja otseteid."</string> <string name="gadget_error_text" msgid="6081085226050792095">"Probleem vidina laadimisel"</string> + <string name="gadget_setup_text" msgid="8274003207686040488">"Seadistamine"</string> <string name="uninstall_system_app_text" msgid="4172046090762920660">"See on süsteemirakendus ja seda ei saa desinstallida."</string> <string name="dream_name" msgid="1530253749244328964">"Rocket Launcher"</string> <string name="folder_hint_text" msgid="6617836969016293992">"Nimetu kaust"</string> @@ -95,6 +97,9 @@ <string name="migration_cling_use_default" msgid="2626475813981258626">"ALUSTA ALGUSEST"</string> <string name="workspace_cling_title" msgid="5626202359865825661">"Korraldage oma ruumi"</string> <string name="workspace_cling_move_item" msgid="528201129978005352">"Taustapildi, vidinate ja seadete haldamiseks puudutage tausta ning hoidke seda all."</string> + <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Taustapildid, vidinad ja seaded"</string> + <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"Kohandamiseks puudutage ja hoidke tausta all"</string> + <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"SELGE"</string> <string name="folder_cling_title" msgid="3894908818693254164">"Siin on kaust"</string> <string name="folder_cling_create_folder" msgid="6158215559475836131">"Sarnase loomiseks vajutage ja hoidke rakendust all, seejärel viige see teise peale."</string> <string name="cling_dismiss" msgid="8962359497601507581">"OK"</string> @@ -107,4 +112,14 @@ <string name="widget_button_text" msgid="2880537293434387943">"Vidinad"</string> <string name="wallpaper_button_text" msgid="8404103075899945851">"Taustapildid"</string> <string name="settings_button_text" msgid="8119458837558863227">"Seaded"</string> + <string name="package_state_enqueued" msgid="6227252464303085641">"Ootamine"</string> + <string name="package_state_downloading" msgid="4088770468458724721">"Allalaadimine"</string> + <string name="package_state_installing" msgid="7588193972189849870">"Installimine"</string> + <string name="package_state_unknown" msgid="7592128424511031410">"Teadmata"</string> + <string name="package_state_error" msgid="7672093962724223588">"Ei taastatud"</string> + <string name="abandoned_clean_all" msgid="5256770727689657618">"Eemalda kõik"</string> + <string name="abandoned_clean_this" msgid="7610119707847920412">"Eemalda"</string> + <string name="abandoned_search" msgid="891119232568284442">"Otsing"</string> + <string name="abandoned_promises_title" msgid="7096178467971716750">"See rakendus ei ole installitud"</string> + <string name="abandoned_promise_explanation" msgid="3990027586878167529">"Selle ikooni rakendust pole installitud. Saate selle eemaldada või rakendust otsida ja käsitsi installida."</string> </resources> diff --git a/res/values-et/strings.xml b/res/values-et/strings.xml index acd072725..3b0deb85b 100644 --- a/res/values-et/strings.xml +++ b/res/values-et/strings.xml @@ -41,7 +41,6 @@ <string name="group_applications" msgid="2103752818818161976">"Rakendused"</string> <string name="group_shortcuts" msgid="9133529424900391877">"Otseteed"</string> <string name="group_widgets" msgid="6704978494073105844">"Vidinad"</string> - <string name="group_wallpapers" msgid="1568191644272224858">"Taustapildid"</string> <string name="completely_out_of_space" msgid="1759078539443491182">"Teie avakuvadel ei ole enam ruumi."</string> <string name="out_of_space" msgid="8365249326091984698">"Sellel avalehel pole enam ruumi."</string> <string name="hotseat_out_of_space" msgid="6304886797358479361">"Kohandataval dokialal pole rohkem ruumi."</string> diff --git a/res/values-eu-rES/strings.xml b/res/values-eu-rES/strings.xml new file mode 100644 index 000000000..4a4c959f4 --- /dev/null +++ b/res/values-eu-rES/strings.xml @@ -0,0 +1,121 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +* Copyright (C) 2008 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. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="application_name" msgid="5181331383435256801">"Abiarazlea3"</string> + <string name="home" msgid="7658288663002113681">"Hasiera"</string> + <string name="uid_name" msgid="7820867637514617527">"Android-en nukleoko aplikazioak"</string> + <string name="folder_name" msgid="7371454440695724752"></string> + <string name="activity_not_found" msgid="8071924732094499514">"Aplikazioa instalatu gabe dago."</string> + <string name="safemode_shortcut_error" msgid="9160126848219158407">"Deskargatutako aplikazioa modu seguruan desgaitu da"</string> + <string name="widgets_tab_label" msgid="2921133187116603919">"Widgetak"</string> + <string name="widget_adder" msgid="3201040140710381657">"Widgetak"</string> + <string name="toggle_weight_watcher" msgid="5645299835184636119">"Erakutsi memoria"</string> + <string name="long_press_widget_to_add" msgid="7699152356777458215">"Eduki ukituta widgeta aukeratzeko."</string> + <string name="market" msgid="2619650989819296998">"Denda"</string> + <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string> + <string name="external_drop_widget_error" msgid="3165821058322217155">"Ezin izan da elementua hasierako pantailan jaregin."</string> + <string name="external_drop_widget_pick_title" msgid="3486317258037690630">"Aukeratu sortu beharreko widgeta"</string> + <string name="rename_folder_label" msgid="3727762225964550653">"Karpetaren izena"</string> + <string name="rename_folder_title" msgid="3771389277707820891">"Aldatu karpetaren izena"</string> + <string name="rename_action" msgid="5559600076028658757">"Ados"</string> + <string name="cancel_action" msgid="7009134900002915310">"Utzi"</string> + <string name="menu_item_add_item" msgid="1264911265836810421">"Gehitu hasierako pantailan"</string> + <string name="group_applications" msgid="3797214114206693605">"Aplikazioak"</string> + <string name="group_shortcuts" msgid="6012256992764410535">"Lasterbideak"</string> + <string name="group_widgets" msgid="1569030723286851002">"Widgetak"</string> + <string name="completely_out_of_space" msgid="6106288382070760318">"Hasierako pantailetan ez dago toki gehiago."</string> + <string name="out_of_space" msgid="4691004494942118364">"Hasierako pantaila honetan ez dago toki gehiago."</string> + <string name="hotseat_out_of_space" msgid="7448809638125333693">"Ez dago toki gehiago Gogokoak erretiluan"</string> + <string name="invalid_hotseat_item" msgid="5779907847267573691">"Widgeta handiegia da Gogokoak erretiluan ezartzeko"</string> + <string name="shortcut_installed" msgid="1701742129426969556">"\"<xliff:g id="NAME">%s</xliff:g>\" lasterbidea sortu da."</string> + <string name="shortcut_uninstalled" msgid="8176767991305701821">"\"<xliff:g id="NAME">%s</xliff:g>\" lasterbidea kendu da."</string> + <string name="shortcut_duplicate" msgid="9167217446062498127">"\"<xliff:g id="NAME">%s</xliff:g>\" lasterbidea lehendik dago."</string> + <string name="title_select_shortcut" msgid="6680642571148153868">"Aukeratu lasterbidea"</string> + <string name="title_select_application" msgid="3280812711670683644">"Aukeratu aplikazioa"</string> + <string name="all_apps_button_label" msgid="9110807029020582876">"Aplikazioak"</string> + <string name="all_apps_home_button_label" msgid="252062713717058851">"Hasiera"</string> + <string name="delete_zone_label_workspace" msgid="4009607676751398685">"Kendu"</string> + <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"Desinstalatu"</string> + <string name="delete_target_label" msgid="1822697352535677073">"Kendu"</string> + <string name="delete_target_uninstall_label" msgid="5100785476250872595">"Desinstalatu"</string> + <string name="info_target_label" msgid="8053346143994679532">"Aplikazioaren informazioa"</string> + <string name="accessibility_search_button" msgid="1628520399424565142">"Bilaketa"</string> + <string name="accessibility_voice_search_button" msgid="4637324840434406584">"Ahots bidezko bilaketa"</string> + <string name="accessibility_all_apps_button" msgid="2603132375383800483">"Aplikazioak"</string> + <string name="accessibility_delete_button" msgid="6466114477993744621">"Kendu"</string> + <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"Desinstalatu eguneratzea"</string> + <string name="cab_menu_delete_app" msgid="7435191475867183689">"Desinstalatu aplikazioa"</string> + <string name="cab_menu_app_info" msgid="8593722221450362342">"Aplikazioaren xehetasunak"</string> + <string name="cab_app_selection_text" msgid="374688303047985416">"Aplikazio bat hautatu da"</string> + <string name="cab_widget_selection_text" msgid="1833458597831541241">"Widget bat hautatu da"</string> + <string name="cab_folder_selection_text" msgid="7999992513806132118">"Karpeta bat hautatu da"</string> + <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"Lasterbide bat hautatu da"</string> + <string name="permlab_install_shortcut" msgid="5632423390354674437">"Instalatu lasterbideak"</string> + <string name="permdesc_install_shortcut" msgid="923466509822011139">"Erabiltzaileak ezer egin gabe lasterbideak gehitzea baimentzen die aplikazioei."</string> + <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"Desinstalatu lasterbideak"</string> + <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"Erabiltzaileak ezer egin gabe lasterbideak kentzea baimentzen die aplikazioei."</string> + <string name="permlab_read_settings" msgid="1941457408239617576">"Irakurri hasierako ezarpenak eta lasterbideak"</string> + <string name="permdesc_read_settings" msgid="5833423719057558387">"Hasierako pantailako ezarpenak eta lasterbideak irakurtzea baimentzen die aplikazioei."</string> + <string name="permlab_write_settings" msgid="3574213698004620587">"Idatzi hasierako ezarpenak eta lasterbideak"</string> + <string name="permdesc_write_settings" msgid="5440712911516509985">"Hasierako pantailako ezarpenak eta lasterbideak aldatzea baimentzen die aplikazioei."</string> + <string name="gadget_error_text" msgid="6081085226050792095">"Arazo bat izan da widgeta kargatzean"</string> + <string name="uninstall_system_app_text" msgid="4172046090762920660">"Sistema-aplikazioa da hau eta ezin da desinstalatu."</string> + <string name="dream_name" msgid="1530253749244328964">"Rocket Launcher"</string> + <string name="folder_hint_text" msgid="6617836969016293992">"Izenik gabeko karpeta"</string> + <string name="workspace_description_format" msgid="2950174241104043327">"%1$d hasierako pantaila"</string> + <string name="default_scroll_format" msgid="7475544710230993317">"%1$d/%2$d orria"</string> + <string name="workspace_scroll_format" msgid="8458889198184077399">"%1$d/%2$d hasierako pantaila"</string> + <string name="apps_customize_apps_scroll_format" msgid="370005296147130238">"%1$d/%2$d aplikazio-orria"</string> + <string name="apps_customize_widgets_scroll_format" msgid="3106209519974971521">"%1$d/%2$d widget-orria"</string> + <string name="first_run_cling_title" msgid="2459738000155917941">"Ongi etorri"</string> + <string name="first_run_cling_description" msgid="6447072552696253358">"Senti zaitez etxean bezala."</string> + <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string> + <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string> + <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"Sortu pantaila gehiago aplikazioak eta karpetak ezartzeko"</string> + <string name="migration_cling_title" msgid="9181776667882933767">"Kopiatu aplikazioen ikonoak"</string> + <string name="migration_cling_description" msgid="2752413805582227644">"Ikonoak eta karpetak aurreko hasierako pantailatik inportatu?"</string> + <string name="migration_cling_copy_apps" msgid="946331230090919440">"KOPIATU IKONOAK"</string> + <string name="migration_cling_use_default" msgid="2626475813981258626">"HASI HUTSETIK"</string> + <string name="workspace_cling_title" msgid="5626202359865825661">"Antolatu zure txokoa"</string> + <string name="workspace_cling_move_item" msgid="528201129978005352">"Eduki ukituta atzeko planoa horma-paperak, widgetak eta ezarpenak kudeatzeko."</string> + <string name="folder_cling_title" msgid="3894908818693254164">"Hortxe duzu karpeta"</string> + <string name="folder_cling_create_folder" msgid="6158215559475836131">"Horrelako bat sortzeko, eduki ukituta aplikazio bat eta eraman beste baten gainera."</string> + <string name="cling_dismiss" msgid="8962359497601507581">"Ados"</string> + <string name="folder_opened" msgid="94695026776264709">"Karpeta ireki da: <xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g>"</string> + <string name="folder_tap_to_close" msgid="1884479294466410023">"Karpeta ixteko, uki ezazu"</string> + <string name="folder_tap_to_rename" msgid="9191075570492871147">"Karpetaren izen berria gordetzeko, uki ezazu"</string> + <string name="folder_closed" msgid="4100806530910930934">"Karpeta itxi da"</string> + <string name="folder_renamed" msgid="1794088362165669656">"Karpetari <xliff:g id="NAME">%1$s</xliff:g> izena eman zaio"</string> + <string name="folder_name_format" msgid="6629239338071103179">"Karpeta: <xliff:g id="NAME">%1$s</xliff:g>"</string> + <string name="widget_button_text" msgid="2880537293434387943">"Widgetak"</string> + <string name="wallpaper_button_text" msgid="8404103075899945851">"Horma-paperak"</string> + <string name="settings_button_text" msgid="8119458837558863227">"Ezarpenak"</string> + <string name="package_state_enqueued" msgid="6227252464303085641">"Zain"</string> + <string name="package_state_downloading" msgid="4088770468458724721">"Deskargatzen"</string> + <string name="package_state_installing" msgid="7588193972189849870">"Instalatzen"</string> + <string name="package_state_unknown" msgid="7592128424511031410">"Ezezaguna"</string> + <string name="package_state_error" msgid="7672093962724223588">"Ez da leheneratu"</string> + <string name="abandoned_clean_all" msgid="5256770727689657618">"Kendu guztiak"</string> + <string name="abandoned_clean_this" msgid="7610119707847920412">"Kendu"</string> + <string name="abandoned_search" msgid="891119232568284442">"Bilatu"</string> + <string name="abandoned_promises_title" msgid="7096178467971716750">"Aplikazio hau ez dago instalatuta"</string> + <string name="abandoned_promise_explanation" msgid="3990027586878167529">"Ikono honen aplikazioa ez dago instalatuta. Ikonoa ken dezakezu, edo aplikazioa bilatu eta eskuz instalatu."</string> +</resources> diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml index a01ea7932..13f40e223 100644 --- a/res/values-fa/strings.xml +++ b/res/values-fa/strings.xml @@ -24,6 +24,7 @@ <string name="uid_name" msgid="7820867637514617527">"برنامههای Android Core"</string> <string name="folder_name" msgid="7371454440695724752"></string> <string name="activity_not_found" msgid="8071924732094499514">"برنامه نصب نشده است."</string> + <string name="safemode_shortcut_error" msgid="9160126848219158407">"برنامه دانلود شده در حالت ایمن غیرفعال شد"</string> <string name="widgets_tab_label" msgid="2921133187116603919">"ابزارکها"</string> <string name="widget_adder" msgid="3201040140710381657">"ابزارکها"</string> <string name="toggle_weight_watcher" msgid="5645299835184636119">"نمایش Mem"</string> @@ -76,6 +77,7 @@ <string name="permlab_write_settings" msgid="3574213698004620587">"نوشتن تنظیمات و میانبرهای صفحه اصلی"</string> <string name="permdesc_write_settings" msgid="5440712911516509985">"به برنامه اجازه میدهد تنظیمات و میانبرها را در صفحه اصلی تغییر دهد."</string> <string name="gadget_error_text" msgid="6081085226050792095">"مشکل در بارگیری ابزارک"</string> + <string name="gadget_setup_text" msgid="8274003207686040488">"تنظیم"</string> <string name="uninstall_system_app_text" msgid="4172046090762920660">"این برنامه سیستمی است و حذف نصب نمیشود."</string> <string name="dream_name" msgid="1530253749244328964">"Rocket Launcher"</string> <string name="folder_hint_text" msgid="6617836969016293992">"پوشه بینام"</string> @@ -95,6 +97,9 @@ <string name="migration_cling_use_default" msgid="2626475813981258626">"شروع تازه"</string> <string name="workspace_cling_title" msgid="5626202359865825661">"فضای خود را سازماندهی کنید"</string> <string name="workspace_cling_move_item" msgid="528201129978005352">"برای مدیریت کاغذدیواری، ابزارکها و تنظیمات، پسزمینه را لمس کرده و نگهدارید."</string> + <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"کاغذدیواریها، ابزارکها و تنظیمات"</string> + <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"برای سفارشی کردن، پسزمینه را لمس کنید و نگهدارید"</string> + <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"متوجه شدم"</string> <string name="folder_cling_title" msgid="3894908818693254164">"اینجا یک پوشه است"</string> <string name="folder_cling_create_folder" msgid="6158215559475836131">"برای ایجاد پوشهای مثل این، یک برنامه را لمس کرده و نگهدارید، سپس آن را روی برنامه دیگر بیاندازید."</string> <string name="cling_dismiss" msgid="8962359497601507581">"تأیید"</string> @@ -107,4 +112,14 @@ <string name="widget_button_text" msgid="2880537293434387943">"ابزارکها"</string> <string name="wallpaper_button_text" msgid="8404103075899945851">"کاغذدیواریها"</string> <string name="settings_button_text" msgid="8119458837558863227">"تنظیمات"</string> + <string name="package_state_enqueued" msgid="6227252464303085641">"در حال انتظار"</string> + <string name="package_state_downloading" msgid="4088770468458724721">"در حال دانلود"</string> + <string name="package_state_installing" msgid="7588193972189849870">"در حال نصب"</string> + <string name="package_state_unknown" msgid="7592128424511031410">"نامشخص"</string> + <string name="package_state_error" msgid="7672093962724223588">"بازیابی نشد"</string> + <string name="abandoned_clean_all" msgid="5256770727689657618">"حذف همه"</string> + <string name="abandoned_clean_this" msgid="7610119707847920412">"حذف"</string> + <string name="abandoned_search" msgid="891119232568284442">"جستجو"</string> + <string name="abandoned_promises_title" msgid="7096178467971716750">"این برنامه نصب نشده است."</string> + <string name="abandoned_promise_explanation" msgid="3990027586878167529">"برنامه برای این نماد نصب نشده است. میتوانید آن را حذف کنید یا سعی کنید برنامه را جستجو کنید و آن را به صورت دستی نصب کنید."</string> </resources> diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml index 9a48ab359..3990a163c 100644 --- a/res/values-fi/strings.xml +++ b/res/values-fi/strings.xml @@ -24,6 +24,7 @@ <string name="uid_name" msgid="7820867637514617527">"Androidin ydinsovellukset"</string> <string name="folder_name" msgid="7371454440695724752"></string> <string name="activity_not_found" msgid="8071924732094499514">"Sovellusta ei ole asennettu."</string> + <string name="safemode_shortcut_error" msgid="9160126848219158407">"Ladattu sovellus poistettiin käytöstä suojatussa tilassa"</string> <string name="widgets_tab_label" msgid="2921133187116603919">"Widgetit"</string> <string name="widget_adder" msgid="3201040140710381657">"Widgetit"</string> <string name="toggle_weight_watcher" msgid="5645299835184636119">"Näytä muisti"</string> @@ -76,6 +77,7 @@ <string name="permlab_write_settings" msgid="3574213698004620587">"kirjoita aloitusruudun asetuksia ja pikakuvakkeita"</string> <string name="permdesc_write_settings" msgid="5440712911516509985">"Antaa sovelluksen muuttaa aloitusruudun asetuksia ja pikakuvakkeita."</string> <string name="gadget_error_text" msgid="6081085226050792095">"Ongelma ladattaessa widgetiä"</string> + <string name="gadget_setup_text" msgid="8274003207686040488">"Asetus"</string> <string name="uninstall_system_app_text" msgid="4172046090762920660">"Tämä on järjestelmäsovellus, eikä sitä voi poistaa."</string> <string name="dream_name" msgid="1530253749244328964">"Sinko"</string> <string name="folder_hint_text" msgid="6617836969016293992">"Nimetön kansio"</string> @@ -95,6 +97,9 @@ <string name="migration_cling_use_default" msgid="2626475813981258626">"ALOITA ALUSTA"</string> <string name="workspace_cling_title" msgid="5626202359865825661">"Järjestä tilasi"</string> <string name="workspace_cling_move_item" msgid="528201129978005352">"Hallitse taustakuvaa, widgetejä ja asetuksia koskettamalla taustaa pitkään."</string> + <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Taustakuvat, widgetit ja asetukset"</string> + <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"Muokkaa taustaa koskettamalla ja painamalla pitkään"</string> + <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"SELVÄ"</string> <string name="folder_cling_title" msgid="3894908818693254164">"Tässä on kansio"</string> <string name="folder_cling_create_folder" msgid="6158215559475836131">"Luo se seuraavasti: kosketa sovellusta pitkään ja siirrä se sitten toisen päälle."</string> <string name="cling_dismiss" msgid="8962359497601507581">"OK"</string> @@ -107,4 +112,14 @@ <string name="widget_button_text" msgid="2880537293434387943">"Widgetit"</string> <string name="wallpaper_button_text" msgid="8404103075899945851">"Taustakuvat"</string> <string name="settings_button_text" msgid="8119458837558863227">"Asetukset"</string> + <string name="package_state_enqueued" msgid="6227252464303085641">"Odottaa"</string> + <string name="package_state_downloading" msgid="4088770468458724721">"Ladataan"</string> + <string name="package_state_installing" msgid="7588193972189849870">"Asennetaan"</string> + <string name="package_state_unknown" msgid="7592128424511031410">"Tuntematon"</string> + <string name="package_state_error" msgid="7672093962724223588">"Ei palautettu"</string> + <string name="abandoned_clean_all" msgid="5256770727689657618">"Poista kaikki"</string> + <string name="abandoned_clean_this" msgid="7610119707847920412">"Poista"</string> + <string name="abandoned_search" msgid="891119232568284442">"Haku"</string> + <string name="abandoned_promises_title" msgid="7096178467971716750">"Sovellusta ei ole asennettu"</string> + <string name="abandoned_promise_explanation" msgid="3990027586878167529">"Kuvakkeen sovellusta ei ole asennettu. Voit poistaa kuvakkeen tai etsiä sovelluksen ja asentaa sen manuaalisesti."</string> </resources> diff --git a/res/values-fr-rCA/strings.xml b/res/values-fr-rCA/strings.xml index 92c5cc489..f42835014 100644 --- a/res/values-fr-rCA/strings.xml +++ b/res/values-fr-rCA/strings.xml @@ -24,6 +24,7 @@ <string name="uid_name" msgid="7820867637514617527">"Applications de base Android"</string> <string name="folder_name" msgid="7371454440695724752"></string> <string name="activity_not_found" msgid="8071924732094499514">"L\'application n\'est pas installée."</string> + <string name="safemode_shortcut_error" msgid="9160126848219158407">"L\'application téléchargée est désactivée en mode sécurisé."</string> <string name="widgets_tab_label" msgid="2921133187116603919">"Widgets"</string> <string name="widget_adder" msgid="3201040140710381657">"Widgets"</string> <string name="toggle_weight_watcher" msgid="5645299835184636119">"Afficher la mémoire"</string> @@ -76,6 +77,7 @@ <string name="permlab_write_settings" msgid="3574213698004620587">"enregistrer les paramètres de la page d\'accueil et des raccourcis"</string> <string name="permdesc_write_settings" msgid="5440712911516509985">"Permet à l\'application de modifier les paramètres et les raccourcis de l\'écran d\'accueil."</string> <string name="gadget_error_text" msgid="6081085226050792095">"Problème lors du chargement du widget"</string> + <string name="gadget_setup_text" msgid="8274003207686040488">"Configuration"</string> <string name="uninstall_system_app_text" msgid="4172046090762920660">"Impossible de désinstaller cette application, car il s\'agit d\'une application système."</string> <string name="dream_name" msgid="1530253749244328964">"Lance-missile"</string> <string name="folder_hint_text" msgid="6617836969016293992">"Dossier sans nom"</string> @@ -95,6 +97,9 @@ <string name="migration_cling_use_default" msgid="2626475813981258626">"DISPOSITION PAR DÉFAUT"</string> <string name="workspace_cling_title" msgid="5626202359865825661">"Organiser son espace personnel"</string> <string name="workspace_cling_move_item" msgid="528201129978005352">"Maintenez votre doigt sur l\'arrière-plan pour gérer les fonds d\'écran, les widgets et les paramètres."</string> + <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Fonds d\'écran, widgets et paramètres"</string> + <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"Maintenez le doigt sur le fond d\'écran pour personnaliser"</string> + <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"J\'ai compris"</string> <string name="folder_cling_title" msgid="3894908818693254164">"Voici un dossier"</string> <string name="folder_cling_create_folder" msgid="6158215559475836131">"Pour créer un dossier comme ça, maintenez votre doigt sur une application, puis déplacez-la sur une autre."</string> <string name="cling_dismiss" msgid="8962359497601507581">"OK"</string> @@ -107,4 +112,14 @@ <string name="widget_button_text" msgid="2880537293434387943">"Widgets"</string> <string name="wallpaper_button_text" msgid="8404103075899945851">"Fonds d\'écran"</string> <string name="settings_button_text" msgid="8119458837558863227">"Paramètres"</string> + <string name="package_state_enqueued" msgid="6227252464303085641">"En attente"</string> + <string name="package_state_downloading" msgid="4088770468458724721">"Téléchargement..."</string> + <string name="package_state_installing" msgid="7588193972189849870">"Installation…"</string> + <string name="package_state_unknown" msgid="7592128424511031410">"Inconnu"</string> + <string name="package_state_error" msgid="7672093962724223588">"Non restauré"</string> + <string name="abandoned_clean_all" msgid="5256770727689657618">"Tout supprimer"</string> + <string name="abandoned_clean_this" msgid="7610119707847920412">"Supprimer"</string> + <string name="abandoned_search" msgid="891119232568284442">"Rechercher"</string> + <string name="abandoned_promises_title" msgid="7096178467971716750">"Cette application n\'est pas installée"</string> + <string name="abandoned_promise_explanation" msgid="3990027586878167529">"L\'application liée à cette icône n\'est pas installée. Vous pouvez la supprimer ou rechercher l\'application et l\'installer manuellement."</string> </resources> diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml index 18732f849..31448f18b 100644 --- a/res/values-fr/strings.xml +++ b/res/values-fr/strings.xml @@ -24,6 +24,7 @@ <string name="uid_name" msgid="7820867637514617527">"Applications de base Android"</string> <string name="folder_name" msgid="7371454440695724752"></string> <string name="activity_not_found" msgid="8071924732094499514">"L\'application n\'est pas installée."</string> + <string name="safemode_shortcut_error" msgid="9160126848219158407">"L\'application téléchargée est désactivée en mode sécurisé."</string> <string name="widgets_tab_label" msgid="2921133187116603919">"Widgets"</string> <string name="widget_adder" msgid="3201040140710381657">"Widgets"</string> <string name="toggle_weight_watcher" msgid="5645299835184636119">"Afficher la mémoire"</string> @@ -76,6 +77,7 @@ <string name="permlab_write_settings" msgid="3574213698004620587">"modifier les paramètres et les raccourcis de l\'écran d\'accueil"</string> <string name="permdesc_write_settings" msgid="5440712911516509985">"Permettre à l\'application de modifier les paramètres et les raccourcis de l\'écran d\'accueil"</string> <string name="gadget_error_text" msgid="6081085226050792095">"Problème lors du chargement du widget."</string> + <string name="gadget_setup_text" msgid="8274003207686040488">"Configuration"</string> <string name="uninstall_system_app_text" msgid="4172046090762920660">"Impossible de désinstaller cette application, car il s\'agit d\'une application système."</string> <string name="dream_name" msgid="1530253749244328964">"Rocket Launcher"</string> <string name="folder_hint_text" msgid="6617836969016293992">"Dossier sans nom"</string> @@ -95,6 +97,9 @@ <string name="migration_cling_use_default" msgid="2626475813981258626">"DISPOSITION PAR DÉFAUT"</string> <string name="workspace_cling_title" msgid="5626202359865825661">"Organisez votre espace"</string> <string name="workspace_cling_move_item" msgid="528201129978005352">"Appuyez de manière prolongée sur l\'arrière-plan pour gérer les fonds d\'écran, les widgets et les paramètres."</string> + <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Fonds d\'écran, widgets et paramètres"</string> + <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"Appuyez de manière prolongée sur l\'arrière-plan pour le personnaliser."</string> + <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"OK"</string> <string name="folder_cling_title" msgid="3894908818693254164">"Voici un dossier"</string> <string name="folder_cling_create_folder" msgid="6158215559475836131">"Pour en créer un, appuyez de manière prolongée sur une application, puis déplacez-la vers une autre."</string> <string name="cling_dismiss" msgid="8962359497601507581">"OK"</string> @@ -107,4 +112,14 @@ <string name="widget_button_text" msgid="2880537293434387943">"Widgets"</string> <string name="wallpaper_button_text" msgid="8404103075899945851">"Fonds d\'écran"</string> <string name="settings_button_text" msgid="8119458837558863227">"Paramètres"</string> + <string name="package_state_enqueued" msgid="6227252464303085641">"En attente"</string> + <string name="package_state_downloading" msgid="4088770468458724721">"Téléchargement…"</string> + <string name="package_state_installing" msgid="7588193972189849870">"Installation…"</string> + <string name="package_state_unknown" msgid="7592128424511031410">"Inconnu"</string> + <string name="package_state_error" msgid="7672093962724223588">"Non restauré"</string> + <string name="abandoned_clean_all" msgid="5256770727689657618">"Tout supprimer"</string> + <string name="abandoned_clean_this" msgid="7610119707847920412">"Supprimer"</string> + <string name="abandoned_search" msgid="891119232568284442">"Rechercher"</string> + <string name="abandoned_promises_title" msgid="7096178467971716750">"Cette application n\'est pas installée"</string> + <string name="abandoned_promise_explanation" msgid="3990027586878167529">"L\'application correspondant à cette icône n\'est pas installée. Vous pouvez supprimer cette dernière, ou essayer de rechercher l\'application et de l\'installer manuellement."</string> </resources> diff --git a/res/values-gl-rES/strings.xml b/res/values-gl-rES/strings.xml new file mode 100644 index 000000000..c053b07fe --- /dev/null +++ b/res/values-gl-rES/strings.xml @@ -0,0 +1,121 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +* Copyright (C) 2008 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. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="application_name" msgid="5181331383435256801">"Launcher3"</string> + <string name="home" msgid="7658288663002113681">"Inicio"</string> + <string name="uid_name" msgid="7820867637514617527">"Aplicacións básicas de Android"</string> + <string name="folder_name" msgid="7371454440695724752"></string> + <string name="activity_not_found" msgid="8071924732094499514">"A aplicación non está instalada"</string> + <string name="safemode_shortcut_error" msgid="9160126848219158407">"Desactivouse a aplicación descargada no modo seguro"</string> + <string name="widgets_tab_label" msgid="2921133187116603919">"Widgets"</string> + <string name="widget_adder" msgid="3201040140710381657">"Widgets"</string> + <string name="toggle_weight_watcher" msgid="5645299835184636119">"Mostrar memoria"</string> + <string name="long_press_widget_to_add" msgid="7699152356777458215">"Mantén premido un widget para seleccionalo."</string> + <string name="market" msgid="2619650989819296998">"Tenda"</string> + <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string> + <string name="external_drop_widget_error" msgid="3165821058322217155">"Non se puido engadir á pantalla de inicio."</string> + <string name="external_drop_widget_pick_title" msgid="3486317258037690630">"Escolle o widget que queiras crear"</string> + <string name="rename_folder_label" msgid="3727762225964550653">"Nome do cartafol"</string> + <string name="rename_folder_title" msgid="3771389277707820891">"Cambiar o nome do cartafol"</string> + <string name="rename_action" msgid="5559600076028658757">"Aceptar"</string> + <string name="cancel_action" msgid="7009134900002915310">"Cancelar"</string> + <string name="menu_item_add_item" msgid="1264911265836810421">"Engadir á pantalla de inicio"</string> + <string name="group_applications" msgid="3797214114206693605">"Aplicacións"</string> + <string name="group_shortcuts" msgid="6012256992764410535">"Atallos"</string> + <string name="group_widgets" msgid="1569030723286851002">"Widgets"</string> + <string name="completely_out_of_space" msgid="6106288382070760318">"Non hai máis espazo nas pantallas de inicio."</string> + <string name="out_of_space" msgid="4691004494942118364">"Non hai máis espazo nesta pantalla de inicio."</string> + <string name="hotseat_out_of_space" msgid="7448809638125333693">"Non hai máis espazo na bandexa de favoritos"</string> + <string name="invalid_hotseat_item" msgid="5779907847267573691">"Este widget é demasiado grande para a bandexa de favoritos"</string> + <string name="shortcut_installed" msgid="1701742129426969556">"Creouse o atallo \"<xliff:g id="NAME">%s</xliff:g>\"."</string> + <string name="shortcut_uninstalled" msgid="8176767991305701821">"Eliminouse o atallo \"<xliff:g id="NAME">%s</xliff:g>\"."</string> + <string name="shortcut_duplicate" msgid="9167217446062498127">"O atallo \"<xliff:g id="NAME">%s</xliff:g>\" xa existe."</string> + <string name="title_select_shortcut" msgid="6680642571148153868">"Escoller un atallo"</string> + <string name="title_select_application" msgid="3280812711670683644">"Escoller unha aplicación"</string> + <string name="all_apps_button_label" msgid="9110807029020582876">"Aplicacións"</string> + <string name="all_apps_home_button_label" msgid="252062713717058851">"Inicio"</string> + <string name="delete_zone_label_workspace" msgid="4009607676751398685">"Eliminar"</string> + <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"Desinstalar"</string> + <string name="delete_target_label" msgid="1822697352535677073">"Eliminar"</string> + <string name="delete_target_uninstall_label" msgid="5100785476250872595">"Desinstalar"</string> + <string name="info_target_label" msgid="8053346143994679532">"Información da aplicación"</string> + <string name="accessibility_search_button" msgid="1628520399424565142">"Buscar"</string> + <string name="accessibility_voice_search_button" msgid="4637324840434406584">"Busca de voz"</string> + <string name="accessibility_all_apps_button" msgid="2603132375383800483">"Aplicacións"</string> + <string name="accessibility_delete_button" msgid="6466114477993744621">"Eliminar"</string> + <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"Desinstalar actualización"</string> + <string name="cab_menu_delete_app" msgid="7435191475867183689">"Desinstalar aplicación"</string> + <string name="cab_menu_app_info" msgid="8593722221450362342">"Detalles da aplicación"</string> + <string name="cab_app_selection_text" msgid="374688303047985416">"1 aplicación seleccionada"</string> + <string name="cab_widget_selection_text" msgid="1833458597831541241">"1 widget seleccionado"</string> + <string name="cab_folder_selection_text" msgid="7999992513806132118">"1 cartafol seleccionado"</string> + <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"1 atallo seleccionado"</string> + <string name="permlab_install_shortcut" msgid="5632423390354674437">"instalar atallos"</string> + <string name="permdesc_install_shortcut" msgid="923466509822011139">"Permite a unha aplicación engadir atallos sen intervención do usuario."</string> + <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"desinstalar atallos"</string> + <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"Permite a unha aplicación eliminar atallos sen intervención do usuario."</string> + <string name="permlab_read_settings" msgid="1941457408239617576">"ler a configuración e os atallos da pantalla de inicio"</string> + <string name="permdesc_read_settings" msgid="5833423719057558387">"Permite a unha aplicación ler a configuración e os atallos da páxina de inicio."</string> + <string name="permlab_write_settings" msgid="3574213698004620587">"modificar a configuración e os atallos da pantalla de inicio"</string> + <string name="permdesc_write_settings" msgid="5440712911516509985">"Permite a unha aplicación cambiar a configuración e os atallos da pantalla de inicio."</string> + <string name="gadget_error_text" msgid="6081085226050792095">"Produciuse un problema ao cargar o widget"</string> + <string name="uninstall_system_app_text" msgid="4172046090762920660">"Esta aplicación é do sistema e non se pode desinstalar."</string> + <string name="dream_name" msgid="1530253749244328964">"Lanzacohetes"</string> + <string name="folder_hint_text" msgid="6617836969016293992">"Cartafol sen nome"</string> + <string name="workspace_description_format" msgid="2950174241104043327">"Pantalla de inicio %1$d"</string> + <string name="default_scroll_format" msgid="7475544710230993317">"Páxina %1$d de %2$d"</string> + <string name="workspace_scroll_format" msgid="8458889198184077399">"Pantalla de inicio %1$d de %2$d"</string> + <string name="apps_customize_apps_scroll_format" msgid="370005296147130238">"Páxina de aplicacións %1$d de %2$d"</string> + <string name="apps_customize_widgets_scroll_format" msgid="3106209519974971521">"Páxina de widgets %1$d de %2$d"</string> + <string name="first_run_cling_title" msgid="2459738000155917941">"Dámosche a benvida"</string> + <string name="first_run_cling_description" msgid="6447072552696253358">"Síntete como na túa casa."</string> + <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string> + <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string> + <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"Crea máis pantallas para aplicacións e cartafoles"</string> + <string name="migration_cling_title" msgid="9181776667882933767">"Copiar iconas das aplicacións"</string> + <string name="migration_cling_description" msgid="2752413805582227644">"Queres importar as iconas e os cartafoles doutras pantallas de inicio?"</string> + <string name="migration_cling_copy_apps" msgid="946331230090919440">"COPIAR ICONAS"</string> + <string name="migration_cling_use_default" msgid="2626475813981258626">"COMEZAR DE CERO"</string> + <string name="workspace_cling_title" msgid="5626202359865825661">"Organiza o espazo"</string> + <string name="workspace_cling_move_item" msgid="528201129978005352">"Mantén premido o fondo para xestionar o fondo de pantalla e máis."</string> + <string name="folder_cling_title" msgid="3894908818693254164">"Isto é un cartafol"</string> + <string name="folder_cling_create_folder" msgid="6158215559475836131">"Para crear un igual, mantén premida a aplicación e móvea sobre outra."</string> + <string name="cling_dismiss" msgid="8962359497601507581">"Aceptar"</string> + <string name="folder_opened" msgid="94695026776264709">"Abriuse o cartafol, <xliff:g id="WIDTH">%1$d</xliff:g> por <xliff:g id="HEIGHT">%2$d</xliff:g>"</string> + <string name="folder_tap_to_close" msgid="1884479294466410023">"Toca para pechar o cartafol"</string> + <string name="folder_tap_to_rename" msgid="9191075570492871147">"Toca para gardar o cambio de nome"</string> + <string name="folder_closed" msgid="4100806530910930934">"Pechouse o cartafol"</string> + <string name="folder_renamed" msgid="1794088362165669656">"O cartafol cambiou o nome a <xliff:g id="NAME">%1$s</xliff:g>"</string> + <string name="folder_name_format" msgid="6629239338071103179">"Cartafol: <xliff:g id="NAME">%1$s</xliff:g>"</string> + <string name="widget_button_text" msgid="2880537293434387943">"Widgets"</string> + <string name="wallpaper_button_text" msgid="8404103075899945851">"Fondos de pantalla"</string> + <string name="settings_button_text" msgid="8119458837558863227">"Configuración"</string> + <string name="package_state_enqueued" msgid="6227252464303085641">"En espera"</string> + <string name="package_state_downloading" msgid="4088770468458724721">"Descargando"</string> + <string name="package_state_installing" msgid="7588193972189849870">"Instalando"</string> + <string name="package_state_unknown" msgid="7592128424511031410">"Descoñecido"</string> + <string name="package_state_error" msgid="7672093962724223588">"Non restaurado"</string> + <string name="abandoned_clean_all" msgid="5256770727689657618">"Eliminar todas"</string> + <string name="abandoned_clean_this" msgid="7610119707847920412">"Eliminar"</string> + <string name="abandoned_search" msgid="891119232568284442">"Buscar"</string> + <string name="abandoned_promises_title" msgid="7096178467971716750">"Esta aplicación non está instalada"</string> + <string name="abandoned_promise_explanation" msgid="3990027586878167529">"A aplicación para esta icona non está instalada. Podes eliminala ou buscar a aplicación e instalala manualmente."</string> +</resources> diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml index b889625bf..0ae90d469 100644 --- a/res/values-hi/strings.xml +++ b/res/values-hi/strings.xml @@ -24,9 +24,10 @@ <string name="uid_name" msgid="7820867637514617527">"Android के मुख्य ऐप्लिकेशन"</string> <string name="folder_name" msgid="7371454440695724752"></string> <string name="activity_not_found" msgid="8071924732094499514">"एप्लिकेशन इंस्टॉल नहीं है."</string> + <string name="safemode_shortcut_error" msgid="9160126848219158407">"डाउनलोड किए गए ऐप्स सुरक्षित मोड में अक्षम है"</string> <string name="widgets_tab_label" msgid="2921133187116603919">"विजेट"</string> <string name="widget_adder" msgid="3201040140710381657">"विजेट"</string> - <string name="toggle_weight_watcher" msgid="5645299835184636119">"स्मृति दिखाएं"</string> + <string name="toggle_weight_watcher" msgid="5645299835184636119">"मेमोरी दिखाएं"</string> <string name="long_press_widget_to_add" msgid="7699152356777458215">"विजेट को चुनने के लिए स्पर्श करके रखें."</string> <string name="market" msgid="2619650989819296998">"खरीदारी करें"</string> <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string> @@ -35,7 +36,7 @@ <string name="rename_folder_label" msgid="3727762225964550653">"फ़ोल्डर का नाम"</string> <string name="rename_folder_title" msgid="3771389277707820891">"फ़ोल्डर का नाम बदलें"</string> <string name="rename_action" msgid="5559600076028658757">"ठीक"</string> - <string name="cancel_action" msgid="7009134900002915310">"रद्द करें"</string> + <string name="cancel_action" msgid="7009134900002915310">"रहने दें"</string> <string name="menu_item_add_item" msgid="1264911265836810421">"होम स्क्रीन में जोड़ें"</string> <string name="group_applications" msgid="3797214114206693605">"ऐप्लिकेशन"</string> <string name="group_shortcuts" msgid="6012256992764410535">"शॉर्टकट"</string> @@ -76,6 +77,7 @@ <string name="permlab_write_settings" msgid="3574213698004620587">"होम सेटिंग और शॉर्टकट लिखें"</string> <string name="permdesc_write_settings" msgid="5440712911516509985">"ऐप्लिकेशन को होम में सेटिंग और शॉर्टकट बदलने देती है."</string> <string name="gadget_error_text" msgid="6081085226050792095">"विजेट लोड करने में समस्या"</string> + <string name="gadget_setup_text" msgid="8274003207686040488">"सेटअप"</string> <string name="uninstall_system_app_text" msgid="4172046090762920660">"यह एक सिस्टम ऐप्लिकेशन है और इसे अनइंस्टॉल नहीं किया जा सकता."</string> <string name="dream_name" msgid="1530253749244328964">"रॉकेट लॉन्चर"</string> <string name="folder_hint_text" msgid="6617836969016293992">"अनामित फ़ोल्डर"</string> @@ -95,6 +97,9 @@ <string name="migration_cling_use_default" msgid="2626475813981258626">"फिर से शुरू करें"</string> <string name="workspace_cling_title" msgid="5626202359865825661">"अपने स्थान को व्यवस्थित करें"</string> <string name="workspace_cling_move_item" msgid="528201129978005352">"वॉलपेपर, विजेट और सेटिंग प्रबंधित करने के लिए पृष्ठभूमि को स्पर्श करके रखें."</string> + <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"वॉलपेपर, विजेट और सेटिंग"</string> + <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"पृष्ठभूमि कस्टमाइज़ करने के लिए स्पर्श करके रखें"</string> + <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"समझ लिया"</string> <string name="folder_cling_title" msgid="3894908818693254164">"यहां एक फ़ोल्डर है"</string> <string name="folder_cling_create_folder" msgid="6158215559475836131">"इसके जैसा कोई एक बनाने के लिए, किसी ऐप्लिकेशन को स्पर्श करके रखें, फिर इसे किसी दूसरे पर ले जाएं."</string> <string name="cling_dismiss" msgid="8962359497601507581">"ठीक"</string> @@ -107,4 +112,14 @@ <string name="widget_button_text" msgid="2880537293434387943">"विजेट"</string> <string name="wallpaper_button_text" msgid="8404103075899945851">"वॉलपेपर"</string> <string name="settings_button_text" msgid="8119458837558863227">"सेटिंग"</string> + <string name="package_state_enqueued" msgid="6227252464303085641">"प्रतीक्षा में"</string> + <string name="package_state_downloading" msgid="4088770468458724721">"डाउनलोड हो रहा है"</string> + <string name="package_state_installing" msgid="7588193972189849870">"इंस्टॉल हो रहा है"</string> + <string name="package_state_unknown" msgid="7592128424511031410">"अज्ञात"</string> + <string name="package_state_error" msgid="7672093962724223588">"पुन:स्थापित नहीं हुआ"</string> + <string name="abandoned_clean_all" msgid="5256770727689657618">"सभी निकालें"</string> + <string name="abandoned_clean_this" msgid="7610119707847920412">"निकालें"</string> + <string name="abandoned_search" msgid="891119232568284442">"खोजें"</string> + <string name="abandoned_promises_title" msgid="7096178467971716750">"यह ऐप्स इंस्टॉल नहीं है"</string> + <string name="abandoned_promise_explanation" msgid="3990027586878167529">"इस आइकन का ऐप्स इंस्टॉल नहीं है. आप उसे निकाल सकते हैं या ऐप्स की खोज करके उसे मैन्युअल रूप से इंस्टॉल कर सकते हैं."</string> </resources> diff --git a/res/values-hr/strings.xml b/res/values-hr/strings.xml index 32f3feb2f..c881077b1 100644 --- a/res/values-hr/strings.xml +++ b/res/values-hr/strings.xml @@ -24,6 +24,7 @@ <string name="uid_name" msgid="7820867637514617527">"Matične aplikacije za Android"</string> <string name="folder_name" msgid="7371454440695724752"></string> <string name="activity_not_found" msgid="8071924732094499514">"Aplikacija nije instalirana."</string> + <string name="safemode_shortcut_error" msgid="9160126848219158407">"Preuzeta aplikacija onemogućena je u Sigurnom načinu rada"</string> <string name="widgets_tab_label" msgid="2921133187116603919">"Widgeti"</string> <string name="widget_adder" msgid="3201040140710381657">"Widgeti"</string> <string name="toggle_weight_watcher" msgid="5645299835184636119">"Prikaži mem"</string> @@ -76,6 +77,7 @@ <string name="permlab_write_settings" msgid="3574213698004620587">"pisanje postavki početnog zaslona i prečaca"</string> <string name="permdesc_write_settings" msgid="5440712911516509985">"Aplikaciji omogućuje promjenu postavki i prečaca na početnom zaslonu."</string> <string name="gadget_error_text" msgid="6081085226050792095">"Problem pri učitavanju widgeta"</string> + <string name="gadget_setup_text" msgid="8274003207686040488">"Postavljanje"</string> <string name="uninstall_system_app_text" msgid="4172046090762920660">"Ovo je aplikacija sustava i ne može se ukloniti."</string> <string name="dream_name" msgid="1530253749244328964">"Lansirna rampa"</string> <string name="folder_hint_text" msgid="6617836969016293992">"Neimenovana mapa"</string> @@ -95,6 +97,9 @@ <string name="migration_cling_use_default" msgid="2626475813981258626">"POKRENI NOVO"</string> <string name="workspace_cling_title" msgid="5626202359865825661">"Organizirajte svoj prostor"</string> <string name="workspace_cling_move_item" msgid="528201129978005352">"Dodirnite i držite pozadinu da biste upravljali pozadinskom slikom, widgetima i postavkama."</string> + <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Pozadinske slike, widgeti i postavke"</string> + <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"Dodirnite i zadržite pozadinu radi prilagodbe"</string> + <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"SHVAĆAM"</string> <string name="folder_cling_title" msgid="3894908818693254164">"Evo mape"</string> <string name="folder_cling_create_folder" msgid="6158215559475836131">"Da biste izradili ovakvu mapu, dodirnite i držite aplikaciju pa je pomaknite preko druge aplikacije."</string> <string name="cling_dismiss" msgid="8962359497601507581">"U redu"</string> @@ -107,4 +112,14 @@ <string name="widget_button_text" msgid="2880537293434387943">"Widgeti"</string> <string name="wallpaper_button_text" msgid="8404103075899945851">"Pozadinske slike"</string> <string name="settings_button_text" msgid="8119458837558863227">"Postavke"</string> + <string name="package_state_enqueued" msgid="6227252464303085641">"Čekanje"</string> + <string name="package_state_downloading" msgid="4088770468458724721">"Preuzimanje"</string> + <string name="package_state_installing" msgid="7588193972189849870">"Instaliranje"</string> + <string name="package_state_unknown" msgid="7592128424511031410">"Nepoznato"</string> + <string name="package_state_error" msgid="7672093962724223588">"Nije vraćeno"</string> + <string name="abandoned_clean_all" msgid="5256770727689657618">"Ukloni sve"</string> + <string name="abandoned_clean_this" msgid="7610119707847920412">"Ukloni"</string> + <string name="abandoned_search" msgid="891119232568284442">"Traži"</string> + <string name="abandoned_promises_title" msgid="7096178467971716750">"Ta aplikacija nije instalirana"</string> + <string name="abandoned_promise_explanation" msgid="3990027586878167529">"Aplikacija ove ikone nije instalirana. Možete je ukloniti ili potražiti aplikaciju i instalirati je ručno."</string> </resources> diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml index 37d505945..08d309558 100644 --- a/res/values-hu/strings.xml +++ b/res/values-hu/strings.xml @@ -24,6 +24,7 @@ <string name="uid_name" msgid="7820867637514617527">"Alap Android-alkalmazások"</string> <string name="folder_name" msgid="7371454440695724752"></string> <string name="activity_not_found" msgid="8071924732094499514">"Az alkalmazás nincs telepítve."</string> + <string name="safemode_shortcut_error" msgid="9160126848219158407">"A letöltött alkalmazás Csökkentett módban ki van kapcsolva"</string> <string name="widgets_tab_label" msgid="2921133187116603919">"Modulok"</string> <string name="widget_adder" msgid="3201040140710381657">"Modulok"</string> <string name="toggle_weight_watcher" msgid="5645299835184636119">"Mem. megjelenítése"</string> @@ -76,6 +77,7 @@ <string name="permlab_write_settings" msgid="3574213698004620587">"Főoldal beállításainak és parancsikonjainak írása"</string> <string name="permdesc_write_settings" msgid="5440712911516509985">"Lehetővé teszi az alkalmazás számára, hogy módosítsa a kezdőképernyő beállításait és parancsikonjait."</string> <string name="gadget_error_text" msgid="6081085226050792095">"Probléma történt a modul betöltésekor"</string> + <string name="gadget_setup_text" msgid="8274003207686040488">"Beállítás"</string> <string name="uninstall_system_app_text" msgid="4172046090762920660">"Ez egy rendszeralkalmazás, és nem lehet eltávolítani."</string> <string name="dream_name" msgid="1530253749244328964">"Aknavető"</string> <string name="folder_hint_text" msgid="6617836969016293992">"Névtelen mappa"</string> @@ -95,6 +97,9 @@ <string name="migration_cling_use_default" msgid="2626475813981258626">"TELJESEN ÚJ"</string> <string name="workspace_cling_title" msgid="5626202359865825661">"Munkaterület rendezése"</string> <string name="workspace_cling_move_item" msgid="528201129978005352">"Érintse meg és tartsa lenyomva a hátteret a háttérkép, modulok és beállítások kezeléséhez."</string> + <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Háttérképek, modulok és beállítások"</string> + <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"Érintse meg és tartsa lenyomva a személyre szabáshoz"</string> + <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"MEGÉRTETTEM"</string> <string name="folder_cling_title" msgid="3894908818693254164">"Itt egy mappa"</string> <string name="folder_cling_create_folder" msgid="6158215559475836131">"Mappa létrehozásához érintse meg és tartsa lenyomva az alkalmazást, majd húzza egy másik fölé."</string> <string name="cling_dismiss" msgid="8962359497601507581">"OK"</string> @@ -107,4 +112,14 @@ <string name="widget_button_text" msgid="2880537293434387943">"Modulok"</string> <string name="wallpaper_button_text" msgid="8404103075899945851">"Háttérképek"</string> <string name="settings_button_text" msgid="8119458837558863227">"Beállítások"</string> + <string name="package_state_enqueued" msgid="6227252464303085641">"Várakozik"</string> + <string name="package_state_downloading" msgid="4088770468458724721">"Letöltés alatt"</string> + <string name="package_state_installing" msgid="7588193972189849870">"Települ"</string> + <string name="package_state_unknown" msgid="7592128424511031410">"Ismeretlen"</string> + <string name="package_state_error" msgid="7672093962724223588">"Nincs visszaállítva"</string> + <string name="abandoned_clean_all" msgid="5256770727689657618">"Az összes eltávolítása"</string> + <string name="abandoned_clean_this" msgid="7610119707847920412">"Eltávolítás"</string> + <string name="abandoned_search" msgid="891119232568284442">"Keresés"</string> + <string name="abandoned_promises_title" msgid="7096178467971716750">"Az alkalmazás nincs telepítve"</string> + <string name="abandoned_promise_explanation" msgid="3990027586878167529">"Az ikonhoz tartozó alkalmazás nincs telepítve. Törölheti az ikont, vagy az alkalmazás megkeresése után manuálisan telepítheti azt."</string> </resources> diff --git a/res/values-hy-rAM/strings.xml b/res/values-hy-rAM/strings.xml index 6e9491bca..4ec39c88c 100644 --- a/res/values-hy-rAM/strings.xml +++ b/res/values-hy-rAM/strings.xml @@ -24,6 +24,7 @@ <string name="uid_name" msgid="7820867637514617527">"Android Core Apps"</string> <string name="folder_name" msgid="7371454440695724752"></string> <string name="activity_not_found" msgid="8071924732094499514">"Ծրագիրը տեղադրված չէ:"</string> + <string name="safemode_shortcut_error" msgid="9160126848219158407">"Ներբեռնված ծրագիրն անջատված է Անվտանգ ռեժիմում"</string> <string name="widgets_tab_label" msgid="2921133187116603919">"Վիջեթներ"</string> <string name="widget_adder" msgid="3201040140710381657">"Վիջեթներ"</string> <string name="toggle_weight_watcher" msgid="5645299835184636119">"Ցուցադրել մեմը"</string> @@ -76,6 +77,7 @@ <string name="permlab_write_settings" msgid="3574213698004620587">"ստեղծել հիմնաէջի կարգավորումներ ու դյուրանցումներ"</string> <string name="permdesc_write_settings" msgid="5440712911516509985">"Ծրագրին թույլ է տալիս փոփոխել հիմնաէջի կարգավորումներն ու դյուրանցումները:"</string> <string name="gadget_error_text" msgid="6081085226050792095">"Վիջեթի բեռնման խնդիր կա"</string> + <string name="gadget_setup_text" msgid="8274003207686040488">"Կարգավորում"</string> <string name="uninstall_system_app_text" msgid="4172046090762920660">"Սա համակարգային ծրագիր է և չի կարող ապատեղադրվել:"</string> <string name="dream_name" msgid="1530253749244328964">"Հրթիռային թողարկիչ"</string> <string name="folder_hint_text" msgid="6617836969016293992">"Անանուն թղթապանակ"</string> @@ -95,6 +97,9 @@ <string name="migration_cling_use_default" msgid="2626475813981258626">"ՄԵԿՆԱՐԿԵԼ ԸՍՏ ԿԱՆԽԱԴՐՎԱԾԻ"</string> <string name="workspace_cling_title" msgid="5626202359865825661">"Կառավարեք ձեր տարածությունը"</string> <string name="workspace_cling_move_item" msgid="528201129978005352">"Հպեք և պահեք հետնաշերտի վրա՝ պաստառները, վիջեթներն ու կարգավորումները կառավարելու համար:"</string> + <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Պաստառներ, վիջեթներ և կարգավորումներ"</string> + <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"Հարմարեցնելու համար հպեք և պահեք հետնաշերտի վրա"</string> + <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"ՀԱՍԿԱՆԱԼԻ Է"</string> <string name="folder_cling_title" msgid="3894908818693254164">"Ահա մի թղթապանակ"</string> <string name="folder_cling_create_folder" msgid="6158215559475836131">"Նման թղթապանակ ստեղծելու համար հպեք և պահեք որևէ ծրագրի վրա, ապա տեղաշարժեք այն մեկ ուրիշ ծրագրի վրա:"</string> <string name="cling_dismiss" msgid="8962359497601507581">"Լավ"</string> @@ -107,4 +112,14 @@ <string name="widget_button_text" msgid="2880537293434387943">"Վիջեթներ"</string> <string name="wallpaper_button_text" msgid="8404103075899945851">"Պաստառներ"</string> <string name="settings_button_text" msgid="8119458837558863227">"Կարգավորումներ"</string> + <string name="package_state_enqueued" msgid="6227252464303085641">"Առկախ է"</string> + <string name="package_state_downloading" msgid="4088770468458724721">"Ներբեռնվում է"</string> + <string name="package_state_installing" msgid="7588193972189849870">"Տեղադրվում է"</string> + <string name="package_state_unknown" msgid="7592128424511031410">"Անհայտ է"</string> + <string name="package_state_error" msgid="7672093962724223588">"Չի վերականգնվել"</string> + <string name="abandoned_clean_all" msgid="5256770727689657618">"Հեռացնել բոլորը"</string> + <string name="abandoned_clean_this" msgid="7610119707847920412">"Հեռացնել"</string> + <string name="abandoned_search" msgid="891119232568284442">"Գտնել"</string> + <string name="abandoned_promises_title" msgid="7096178467971716750">"Այս ծրագիրը տեղադրված չէ:"</string> + <string name="abandoned_promise_explanation" msgid="3990027586878167529">"Այս պատկերակի ծրագիրը տեղադրված չէ: Դուք կարող եք հեռացնել այն կամ գտնել ծրագիրը և տեղադրել այն ձեռքով:"</string> </resources> diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml index d5df63bfa..137e3cc7d 100644 --- a/res/values-in/strings.xml +++ b/res/values-in/strings.xml @@ -24,6 +24,7 @@ <string name="uid_name" msgid="7820867637514617527">"Aplikasi Inti Android"</string> <string name="folder_name" msgid="7371454440695724752"></string> <string name="activity_not_found" msgid="8071924732094499514">"Aplikasi tidak dipasang."</string> + <string name="safemode_shortcut_error" msgid="9160126848219158407">"Aplikasi yang diunduh dinonaktifkan dalam mode Aman"</string> <string name="widgets_tab_label" msgid="2921133187116603919">"Widget"</string> <string name="widget_adder" msgid="3201040140710381657">"Widget"</string> <string name="toggle_weight_watcher" msgid="5645299835184636119">"Tampilkan Memori"</string> @@ -76,6 +77,7 @@ <string name="permlab_write_settings" msgid="3574213698004620587">"menulis setelan dan pintasan layar Utama"</string> <string name="permdesc_write_settings" msgid="5440712911516509985">"Mengizinkan aplikasi mengubah setelan dan pintasan di layar Utama."</string> <string name="gadget_error_text" msgid="6081085226050792095">"Masalah memuat widget"</string> + <string name="gadget_setup_text" msgid="8274003207686040488">"Siapkan"</string> <string name="uninstall_system_app_text" msgid="4172046090762920660">"Ini adalah aplikasi sistem dan tidak dapat dicopot pemasangannya."</string> <string name="dream_name" msgid="1530253749244328964">"Rocket Launcher"</string> <string name="folder_hint_text" msgid="6617836969016293992">"Folder Tanpa Nama"</string> @@ -95,6 +97,9 @@ <string name="migration_cling_use_default" msgid="2626475813981258626">"MULAI DARI AWAL"</string> <string name="workspace_cling_title" msgid="5626202359865825661">"Kelola ruang Anda"</string> <string name="workspace_cling_move_item" msgid="528201129978005352">"Sentuh lama latar belakang untuk mengelola wallpaper, widget, dan setelan."</string> + <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Wallpaper, widget, & setelan"</string> + <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"Sentuh & tahan latar belakang untuk menyesuaikan"</string> + <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"MENGERTI"</string> <string name="folder_cling_title" msgid="3894908818693254164">"Ini adalah folder"</string> <string name="folder_cling_create_folder" msgid="6158215559475836131">"Untuk membuat seperti yang ini, sentuh lama aplikasi, lalu pindahkan ke atas aplikasi lain."</string> <string name="cling_dismiss" msgid="8962359497601507581">"Oke"</string> @@ -107,4 +112,14 @@ <string name="widget_button_text" msgid="2880537293434387943">"Widget"</string> <string name="wallpaper_button_text" msgid="8404103075899945851">"Wallpaper"</string> <string name="settings_button_text" msgid="8119458837558863227">"Setelan"</string> + <string name="package_state_enqueued" msgid="6227252464303085641">"Menunggu"</string> + <string name="package_state_downloading" msgid="4088770468458724721">"Mengunduh"</string> + <string name="package_state_installing" msgid="7588193972189849870">"Memasang"</string> + <string name="package_state_unknown" msgid="7592128424511031410">"Tidak dikenal"</string> + <string name="package_state_error" msgid="7672093962724223588">"Tak dipulihkan"</string> + <string name="abandoned_clean_all" msgid="5256770727689657618">"Buang Semua"</string> + <string name="abandoned_clean_this" msgid="7610119707847920412">"Buang"</string> + <string name="abandoned_search" msgid="891119232568284442">"Telusuri"</string> + <string name="abandoned_promises_title" msgid="7096178467971716750">"Aplikasi ini belum terpasang"</string> + <string name="abandoned_promise_explanation" msgid="3990027586878167529">"Aplikasi untuk ikon ini belum dipasang. Anda dapat membuangnya, atau menelusuri aplikasi dan memasangnya secara manual."</string> </resources> diff --git a/res/values-is-rIS/strings.xml b/res/values-is-rIS/strings.xml new file mode 100644 index 000000000..71f0edea9 --- /dev/null +++ b/res/values-is-rIS/strings.xml @@ -0,0 +1,121 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +* Copyright (C) 2008 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. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="application_name" msgid="5181331383435256801">"Launcher3"</string> + <string name="home" msgid="7658288663002113681">"Heim"</string> + <string name="uid_name" msgid="7820867637514617527">"Kjarnaforrit Android"</string> + <string name="folder_name" msgid="7371454440695724752"></string> + <string name="activity_not_found" msgid="8071924732094499514">"Forritið er ekki uppsett."</string> + <string name="safemode_shortcut_error" msgid="9160126848219158407">"Sótt forrit er óvirkt í öryggisstillingu"</string> + <string name="widgets_tab_label" msgid="2921133187116603919">"Græjur"</string> + <string name="widget_adder" msgid="3201040140710381657">"Græjur"</string> + <string name="toggle_weight_watcher" msgid="5645299835184636119">"Sýna minni"</string> + <string name="long_press_widget_to_add" msgid="7699152356777458215">"Haltu fingri á græju til að grípa hana."</string> + <string name="market" msgid="2619650989819296998">"Verslun"</string> + <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string> + <string name="external_drop_widget_error" msgid="3165821058322217155">"Ekki er hægt að sleppa atriði á þennan heimaskjá."</string> + <string name="external_drop_widget_pick_title" msgid="3486317258037690630">"Veldu græju til að búa til"</string> + <string name="rename_folder_label" msgid="3727762225964550653">"Möppuheiti"</string> + <string name="rename_folder_title" msgid="3771389277707820891">"Endurnefna möppu"</string> + <string name="rename_action" msgid="5559600076028658757">"Í lagi"</string> + <string name="cancel_action" msgid="7009134900002915310">"Hætta við"</string> + <string name="menu_item_add_item" msgid="1264911265836810421">"Bæta á heimaskjá"</string> + <string name="group_applications" msgid="3797214114206693605">"Forrit"</string> + <string name="group_shortcuts" msgid="6012256992764410535">"Flýtileiðir"</string> + <string name="group_widgets" msgid="1569030723286851002">"Græjur"</string> + <string name="completely_out_of_space" msgid="6106288382070760318">"Heimaskjáirnir þínir eru fullskipaðir."</string> + <string name="out_of_space" msgid="4691004494942118364">"Ekki meira pláss á þessum heimaskjá."</string> + <string name="hotseat_out_of_space" msgid="7448809638125333693">"Ekki meira pláss í bakka fyrir uppáhald"</string> + <string name="invalid_hotseat_item" msgid="5779907847267573691">"Þessi græja er of stór fyrir bakkann fyrir uppáhald"</string> + <string name="shortcut_installed" msgid="1701742129426969556">"Flýtileiðin „<xliff:g id="NAME">%s</xliff:g>“ var búin til."</string> + <string name="shortcut_uninstalled" msgid="8176767991305701821">"Flýtileiðin „<xliff:g id="NAME">%s</xliff:g>“ var fjarlægð."</string> + <string name="shortcut_duplicate" msgid="9167217446062498127">"Flýtileiðin „<xliff:g id="NAME">%s</xliff:g>“ er þegar til."</string> + <string name="title_select_shortcut" msgid="6680642571148153868">"Veldu flýtileið"</string> + <string name="title_select_application" msgid="3280812711670683644">"Veldu forrit"</string> + <string name="all_apps_button_label" msgid="9110807029020582876">"Forrit"</string> + <string name="all_apps_home_button_label" msgid="252062713717058851">"Heim"</string> + <string name="delete_zone_label_workspace" msgid="4009607676751398685">"Fjarlægja"</string> + <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"Eyða"</string> + <string name="delete_target_label" msgid="1822697352535677073">"Fjarlægja"</string> + <string name="delete_target_uninstall_label" msgid="5100785476250872595">"Eyða"</string> + <string name="info_target_label" msgid="8053346143994679532">"Upplýsingar um forrit"</string> + <string name="accessibility_search_button" msgid="1628520399424565142">"Leita"</string> + <string name="accessibility_voice_search_button" msgid="4637324840434406584">"Raddleit"</string> + <string name="accessibility_all_apps_button" msgid="2603132375383800483">"Forrit"</string> + <string name="accessibility_delete_button" msgid="6466114477993744621">"Fjarlægja"</string> + <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"Fjarlægja uppfærslu"</string> + <string name="cab_menu_delete_app" msgid="7435191475867183689">"Fjarlægja forrit"</string> + <string name="cab_menu_app_info" msgid="8593722221450362342">"Upplýsingar um forrit"</string> + <string name="cab_app_selection_text" msgid="374688303047985416">"1 forrit valið"</string> + <string name="cab_widget_selection_text" msgid="1833458597831541241">"1 græja valin"</string> + <string name="cab_folder_selection_text" msgid="7999992513806132118">"1 mappa valin"</string> + <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"1 flýtileið valin"</string> + <string name="permlab_install_shortcut" msgid="5632423390354674437">"setja upp flýtileiðir"</string> + <string name="permdesc_install_shortcut" msgid="923466509822011139">"Leyfir forriti að bæta við flýtileiðum án íhlutunar notanda."</string> + <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"fjarlægja flýtileiðir"</string> + <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"Leyfir forriti að fjarlægja flýtileiðir án íhlutunar notanda."</string> + <string name="permlab_read_settings" msgid="1941457408239617576">"lesa stillingar og flýtileiðir heimaskjás"</string> + <string name="permdesc_read_settings" msgid="5833423719057558387">"Leyfir forriti að lesa stillingar og flýtileiðir heimaskjás."</string> + <string name="permlab_write_settings" msgid="3574213698004620587">"skrifa stillingar og flýtileiðir heimaskjás"</string> + <string name="permdesc_write_settings" msgid="5440712911516509985">"Leyfir forriti að breyta stillingum og flýtileiðum heimaskjás."</string> + <string name="gadget_error_text" msgid="6081085226050792095">"Vandamál við að hlaða græju"</string> + <string name="uninstall_system_app_text" msgid="4172046090762920660">"Þetta er kerfisforrit sem ekki er hægt að fjarlægja."</string> + <string name="dream_name" msgid="1530253749244328964">"Eldflaugapallur"</string> + <string name="folder_hint_text" msgid="6617836969016293992">"Ónefnd mappa"</string> + <string name="workspace_description_format" msgid="2950174241104043327">"Heimaskjár %1$d"</string> + <string name="default_scroll_format" msgid="7475544710230993317">"Síða %1$d af %2$d"</string> + <string name="workspace_scroll_format" msgid="8458889198184077399">"Heimaskjár %1$d af %2$d"</string> + <string name="apps_customize_apps_scroll_format" msgid="370005296147130238">"Forritasíða %1$d af %2$d"</string> + <string name="apps_customize_widgets_scroll_format" msgid="3106209519974971521">"Græjusíða %1$d af %2$d"</string> + <string name="first_run_cling_title" msgid="2459738000155917941">"Komdu fagnandi"</string> + <string name="first_run_cling_description" msgid="6447072552696253358">"Komdu þér vel fyrir."</string> + <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string> + <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string> + <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"Búðu til fleiri skjái fyrir forrit og möppur"</string> + <string name="migration_cling_title" msgid="9181776667882933767">"Afritaðu forritatáknin þín"</string> + <string name="migration_cling_description" msgid="2752413805582227644">"Flytja inn tákn og möppur af eldri heimaskjáum?"</string> + <string name="migration_cling_copy_apps" msgid="946331230090919440">"AFRITA TÁKN"</string> + <string name="migration_cling_use_default" msgid="2626475813981258626">"BYRJA UPP Á NÝTT"</string> + <string name="workspace_cling_title" msgid="5626202359865825661">"Settu hlutina á sína staði"</string> + <string name="workspace_cling_move_item" msgid="528201129978005352">"Haltu inni á bakgrunni til að stjórna veggfóðri, græjum og stillingum."</string> + <string name="folder_cling_title" msgid="3894908818693254164">"Hér er mappa"</string> + <string name="folder_cling_create_folder" msgid="6158215559475836131">"Til að búa til svona skaltu draga forrit yfir á annað forrit."</string> + <string name="cling_dismiss" msgid="8962359497601507581">"Í lagi"</string> + <string name="folder_opened" msgid="94695026776264709">"Mappa opnuð, <xliff:g id="WIDTH">%1$d</xliff:g> sinnum <xliff:g id="HEIGHT">%2$d</xliff:g>"</string> + <string name="folder_tap_to_close" msgid="1884479294466410023">"Snertu til að loka möppunni"</string> + <string name="folder_tap_to_rename" msgid="9191075570492871147">"Snertu til að staðfesta nýtt heiti"</string> + <string name="folder_closed" msgid="4100806530910930934">"Möppu lokað"</string> + <string name="folder_renamed" msgid="1794088362165669656">"Heiti möppu breytt í <xliff:g id="NAME">%1$s</xliff:g>"</string> + <string name="folder_name_format" msgid="6629239338071103179">"Mappa: <xliff:g id="NAME">%1$s</xliff:g>"</string> + <string name="widget_button_text" msgid="2880537293434387943">"Græjur"</string> + <string name="wallpaper_button_text" msgid="8404103075899945851">"Veggfóður"</string> + <string name="settings_button_text" msgid="8119458837558863227">"Stillingar"</string> + <string name="package_state_enqueued" msgid="6227252464303085641">"Bíður"</string> + <string name="package_state_downloading" msgid="4088770468458724721">"Sækir"</string> + <string name="package_state_installing" msgid="7588193972189849870">"Setur upp"</string> + <string name="package_state_unknown" msgid="7592128424511031410">"Óþekkt"</string> + <string name="package_state_error" msgid="7672093962724223588">"Ekki endurheimt"</string> + <string name="abandoned_clean_all" msgid="5256770727689657618">"Fjarlægja öll"</string> + <string name="abandoned_clean_this" msgid="7610119707847920412">"Fjarlægja"</string> + <string name="abandoned_search" msgid="891119232568284442">"Leita"</string> + <string name="abandoned_promises_title" msgid="7096178467971716750">"Þetta forrit er ekki uppsett"</string> + <string name="abandoned_promise_explanation" msgid="3990027586878167529">"Forritið fyrir þetta tákn er ekki uppsett. Þú getur fjarlægt það eða leitað að forritinu og sett það upp handvirkt."</string> +</resources> diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml index 20451d135..b01b25174 100644 --- a/res/values-it/strings.xml +++ b/res/values-it/strings.xml @@ -24,6 +24,7 @@ <string name="uid_name" msgid="7820867637514617527">"Applicazioni di base Android"</string> <string name="folder_name" msgid="7371454440695724752"></string> <string name="activity_not_found" msgid="8071924732094499514">"App non installata."</string> + <string name="safemode_shortcut_error" msgid="9160126848219158407">"L\'app scaricata è stata disattivata in modalità provvisoria"</string> <string name="widgets_tab_label" msgid="2921133187116603919">"Widget"</string> <string name="widget_adder" msgid="3201040140710381657">"Widget"</string> <string name="toggle_weight_watcher" msgid="5645299835184636119">"Mostra Mem"</string> @@ -76,6 +77,7 @@ <string name="permlab_write_settings" msgid="3574213698004620587">"creazione di impostazioni e scorciatoie in Home"</string> <string name="permdesc_write_settings" msgid="5440712911516509985">"Consente all\'app di modificare le impostazioni e le scorciatoie in Home."</string> <string name="gadget_error_text" msgid="6081085226050792095">"Errore durante il caricamento del widget"</string> + <string name="gadget_setup_text" msgid="8274003207686040488">"Configurazione"</string> <string name="uninstall_system_app_text" msgid="4172046090762920660">"Questa è un\'app di sistema e non può essere disinstallata."</string> <string name="dream_name" msgid="1530253749244328964">"Lanciamissili"</string> <string name="folder_hint_text" msgid="6617836969016293992">"Cartella senza nome"</string> @@ -95,6 +97,9 @@ <string name="migration_cling_use_default" msgid="2626475813981258626">"RICOMINCIA"</string> <string name="workspace_cling_title" msgid="5626202359865825661">"Organizza il tuo spazio"</string> <string name="workspace_cling_move_item" msgid="528201129978005352">"Tocca e tieni premuto lo sfondo per gestire sfondi, widget e impostazioni."</string> + <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Sfondi, widget e impostazioni"</string> + <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"Tocca lo sfondo e tieni premuto per personalizzare"</string> + <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"OK"</string> <string name="folder_cling_title" msgid="3894908818693254164">"Ecco una cartella"</string> <string name="folder_cling_create_folder" msgid="6158215559475836131">"Per crearne una simile, tocca un\'app e tieni premuto, dopodiché spostala sopra un\'altra."</string> <string name="cling_dismiss" msgid="8962359497601507581">"OK"</string> @@ -107,4 +112,14 @@ <string name="widget_button_text" msgid="2880537293434387943">"Widget"</string> <string name="wallpaper_button_text" msgid="8404103075899945851">"Sfondi"</string> <string name="settings_button_text" msgid="8119458837558863227">"Impostazioni"</string> + <string name="package_state_enqueued" msgid="6227252464303085641">"In attesa"</string> + <string name="package_state_downloading" msgid="4088770468458724721">"Download..."</string> + <string name="package_state_installing" msgid="7588193972189849870">"Installazione..."</string> + <string name="package_state_unknown" msgid="7592128424511031410">"Sconosciuto"</string> + <string name="package_state_error" msgid="7672093962724223588">"Non ripristinato"</string> + <string name="abandoned_clean_all" msgid="5256770727689657618">"Rimuovi tutto"</string> + <string name="abandoned_clean_this" msgid="7610119707847920412">"Rimuovi"</string> + <string name="abandoned_search" msgid="891119232568284442">"Cerca"</string> + <string name="abandoned_promises_title" msgid="7096178467971716750">"L\'app non è installata"</string> + <string name="abandoned_promise_explanation" msgid="3990027586878167529">"L\'app per questa icona non è installata. Puoi rimuoverla o cercare l\'app e installarla manualmente."</string> </resources> diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml index 08d965399..6318207ff 100644 --- a/res/values-iw/strings.xml +++ b/res/values-iw/strings.xml @@ -24,6 +24,7 @@ <string name="uid_name" msgid="7820867637514617527">"אפליקציות הליבה של Android"</string> <string name="folder_name" msgid="7371454440695724752"></string> <string name="activity_not_found" msgid="8071924732094499514">"האפליקציה לא מותקנת."</string> + <string name="safemode_shortcut_error" msgid="9160126848219158407">"אפליקציה שהורדת הושבתה במצב בטוח"</string> <string name="widgets_tab_label" msgid="2921133187116603919">"רכיבי ווידג\'ט"</string> <string name="widget_adder" msgid="3201040140710381657">"רכיבי ווידג\'ט"</string> <string name="toggle_weight_watcher" msgid="5645299835184636119">"הצג זכרון"</string> @@ -76,6 +77,7 @@ <string name="permlab_write_settings" msgid="3574213698004620587">"כתוב הגדרות וקיצורי דרך של דף הבית"</string> <string name="permdesc_write_settings" msgid="5440712911516509985">"מאפשר לאפליקציה לשנות את ההגדרות וקיצורי הדרך בדף הבית."</string> <string name="gadget_error_text" msgid="6081085226050792095">"בעיה בטעינת ווידג\'ט"</string> + <string name="gadget_setup_text" msgid="8274003207686040488">"הגדר"</string> <string name="uninstall_system_app_text" msgid="4172046090762920660">"זוהי אפליקציית מערכת ולא ניתן להסיר את התקנתה."</string> <string name="dream_name" msgid="1530253749244328964">"Rocket Launcher"</string> <string name="folder_hint_text" msgid="6617836969016293992">"תיקיה ללא שם"</string> @@ -95,6 +97,9 @@ <string name="migration_cling_use_default" msgid="2626475813981258626">"התחל דף חדש"</string> <string name="workspace_cling_title" msgid="5626202359865825661">"ארגן את אזור העבודה שלך"</string> <string name="workspace_cling_move_item" msgid="528201129978005352">"גע נגיעה רציפה ברקע כדי לנהל את הטפט, רכיבי הווידג\'ט וההגדרות."</string> + <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"טפטים, ווידג\'טים והגדרות"</string> + <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"גע והחזק ברקע לביצוע התאמה אישית"</string> + <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"הבנתי"</string> <string name="folder_cling_title" msgid="3894908818693254164">"הנה תיקייה"</string> <string name="folder_cling_create_folder" msgid="6158215559475836131">"כדי ליצור תיקייה כזו, גע נגיעה רציפה באפליקציה, ולאחר מכן גרור ושחרר אותו על-גבי אפליקציה אחרת."</string> <string name="cling_dismiss" msgid="8962359497601507581">"אישור"</string> @@ -107,4 +112,14 @@ <string name="widget_button_text" msgid="2880537293434387943">"רכיבי ווידג\'ט"</string> <string name="wallpaper_button_text" msgid="8404103075899945851">"טפטים"</string> <string name="settings_button_text" msgid="8119458837558863227">"הגדרות"</string> + <string name="package_state_enqueued" msgid="6227252464303085641">"ממתין"</string> + <string name="package_state_downloading" msgid="4088770468458724721">"מוריד"</string> + <string name="package_state_installing" msgid="7588193972189849870">"מתקין"</string> + <string name="package_state_unknown" msgid="7592128424511031410">"לא ידוע"</string> + <string name="package_state_error" msgid="7672093962724223588">"לא שוחזרה"</string> + <string name="abandoned_clean_all" msgid="5256770727689657618">"הסר את הכל"</string> + <string name="abandoned_clean_this" msgid="7610119707847920412">"הסר"</string> + <string name="abandoned_search" msgid="891119232568284442">"חפש"</string> + <string name="abandoned_promises_title" msgid="7096178467971716750">"אפליקציה זו אינה מותקנת"</string> + <string name="abandoned_promise_explanation" msgid="3990027586878167529">"האפליקציה של סמל זה אינה מותקנת. ניתן להסיר אותו, או לחפש את האפליקציה ולהתקין אותה ידנית."</string> </resources> diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml index ad5e8ff70..232845af0 100644 --- a/res/values-ja/strings.xml +++ b/res/values-ja/strings.xml @@ -24,6 +24,7 @@ <string name="uid_name" msgid="7820867637514617527">"Android Core Apps"</string> <string name="folder_name" msgid="7371454440695724752"></string> <string name="activity_not_found" msgid="8071924732094499514">"このアプリはインストールされていません。"</string> + <string name="safemode_shortcut_error" msgid="9160126848219158407">"ダウンロードしたアプリは、セーフモードでは無効です"</string> <string name="widgets_tab_label" msgid="2921133187116603919">"ウィジェット"</string> <string name="widget_adder" msgid="3201040140710381657">"ウィジェット"</string> <string name="toggle_weight_watcher" msgid="5645299835184636119">"メモリーを表示"</string> @@ -76,6 +77,7 @@ <string name="permlab_write_settings" msgid="3574213698004620587">"ホームの設定とショートカットの書き込み"</string> <string name="permdesc_write_settings" msgid="5440712911516509985">"ホームの設定とショートカットの変更をアプリに許可します。"</string> <string name="gadget_error_text" msgid="6081085226050792095">"ウィジェットを表示できません"</string> + <string name="gadget_setup_text" msgid="8274003207686040488">"セットアップ"</string> <string name="uninstall_system_app_text" msgid="4172046090762920660">"このシステムアプリはアンインストールできません。"</string> <string name="dream_name" msgid="1530253749244328964">"Rocket Launcher"</string> <string name="folder_hint_text" msgid="6617836969016293992">"名前のないフォルダ"</string> @@ -95,6 +97,9 @@ <string name="migration_cling_use_default" msgid="2626475813981258626">"初期状態にリセットする"</string> <string name="workspace_cling_title" msgid="5626202359865825661">"スペースを整理"</string> <string name="workspace_cling_move_item" msgid="528201129978005352">"壁紙、ウィジェット、設定を管理するには、背景を押し続けます。"</string> + <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"壁紙、ウィジェット、設定"</string> + <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"カスタマイズするにはバックグラウンドを押し続けます"</string> + <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"OK"</string> <string name="folder_cling_title" msgid="3894908818693254164">"これがフォルダです"</string> <string name="folder_cling_create_folder" msgid="6158215559475836131">"これと同じフォルダを作成するには、アプリを押し続けてから別のアプリの上に移動します。"</string> <string name="cling_dismiss" msgid="8962359497601507581">"OK"</string> @@ -107,4 +112,14 @@ <string name="widget_button_text" msgid="2880537293434387943">"ウィジェット"</string> <string name="wallpaper_button_text" msgid="8404103075899945851">"壁紙"</string> <string name="settings_button_text" msgid="8119458837558863227">"設定"</string> + <string name="package_state_enqueued" msgid="6227252464303085641">"待機中"</string> + <string name="package_state_downloading" msgid="4088770468458724721">"ダウンロード中"</string> + <string name="package_state_installing" msgid="7588193972189849870">"インストール中"</string> + <string name="package_state_unknown" msgid="7592128424511031410">"不明"</string> + <string name="package_state_error" msgid="7672093962724223588">"復元失敗"</string> + <string name="abandoned_clean_all" msgid="5256770727689657618">"すべて削除"</string> + <string name="abandoned_clean_this" msgid="7610119707847920412">"削除"</string> + <string name="abandoned_search" msgid="891119232568284442">"検索"</string> + <string name="abandoned_promises_title" msgid="7096178467971716750">"このアプリはインストールされていません"</string> + <string name="abandoned_promise_explanation" msgid="3990027586878167529">"このアイコンのアプリはインストールされていません。このアイコンは削除できます。または、手動でアプリを検索してインストールしください。"</string> </resources> diff --git a/res/values-ka-rGE/strings.xml b/res/values-ka-rGE/strings.xml index 086df7222..2fb51f541 100644 --- a/res/values-ka-rGE/strings.xml +++ b/res/values-ka-rGE/strings.xml @@ -24,6 +24,7 @@ <string name="uid_name" msgid="7820867637514617527">"Android-ის ბირთვის აპები"</string> <string name="folder_name" msgid="7371454440695724752"></string> <string name="activity_not_found" msgid="8071924732094499514">"აპი არ არის დაყენებული."</string> + <string name="safemode_shortcut_error" msgid="9160126848219158407">"უსაფრთხო რეჟიმში ჩამოტვირთული აპი გაუქმებულია"</string> <string name="widgets_tab_label" msgid="2921133187116603919">"ვიჯეტები"</string> <string name="widget_adder" msgid="3201040140710381657">"ვიჯეტები"</string> <string name="toggle_weight_watcher" msgid="5645299835184636119">"Mem-ის ჩვენება"</string> @@ -76,6 +77,7 @@ <string name="permlab_write_settings" msgid="3574213698004620587">"მთავარი ეკრანის პარამეტრებისა და მალსახმობების ჩაწერა"</string> <string name="permdesc_write_settings" msgid="5440712911516509985">"აპისთვის მთავარი ეკრანის პარამეტრებისა და მალსახმობების შეცვლის უფლების მიცემა."</string> <string name="gadget_error_text" msgid="6081085226050792095">"პრობლემა ვიჯეტის ჩატვირთვისას"</string> + <string name="gadget_setup_text" msgid="8274003207686040488">"დაყენება"</string> <string name="uninstall_system_app_text" msgid="4172046090762920660">"ეს სისტემური აპია და მისი წაშლა შეუძლებელია."</string> <string name="dream_name" msgid="1530253749244328964">"ფეიერვერკი"</string> <string name="folder_hint_text" msgid="6617836969016293992">"უსახელო საქაღალდე"</string> @@ -95,6 +97,9 @@ <string name="migration_cling_use_default" msgid="2626475813981258626">"სტანდარტული განლაგება"</string> <string name="workspace_cling_title" msgid="5626202359865825661">"თქვენი სივრცის ორგანიზება"</string> <string name="workspace_cling_move_item" msgid="528201129978005352">"თუ გსურთ ფონების, ვიჯეტების და პარამეტრების მართვა, შეეხეთ და არ აუშვათ ფონს."</string> + <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"ფონები, ვიჯეტები, & პარამეტრები"</string> + <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"მოსარგებად შეეხეთ & დააყოვნეთ ფონზე"</string> + <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"გასაგებია"</string> <string name="folder_cling_title" msgid="3894908818693254164">"აი, საქაღალდე"</string> <string name="folder_cling_create_folder" msgid="6158215559475836131">"ასეთის შესაქმნელად, შეეხეთ და დააყოვნეთ აპზე, ხოლო შემდეგ გადააჩოჩეთ შემდეგზე."</string> <string name="cling_dismiss" msgid="8962359497601507581">"კარგი"</string> @@ -107,4 +112,14 @@ <string name="widget_button_text" msgid="2880537293434387943">"ვიჯეტები"</string> <string name="wallpaper_button_text" msgid="8404103075899945851">"ფონები"</string> <string name="settings_button_text" msgid="8119458837558863227">"პარამეტრები"</string> + <string name="package_state_enqueued" msgid="6227252464303085641">"მოცდა..."</string> + <string name="package_state_downloading" msgid="4088770468458724721">"ჩამოტვირთვა..."</string> + <string name="package_state_installing" msgid="7588193972189849870">"ინსტალაცია..."</string> + <string name="package_state_unknown" msgid="7592128424511031410">"უცნობი"</string> + <string name="package_state_error" msgid="7672093962724223588">"არ აღდგა"</string> + <string name="abandoned_clean_all" msgid="5256770727689657618">"ყველას ამოშლა"</string> + <string name="abandoned_clean_this" msgid="7610119707847920412">"ამოშლა"</string> + <string name="abandoned_search" msgid="891119232568284442">"ძიება"</string> + <string name="abandoned_promises_title" msgid="7096178467971716750">"ეს აპი დაყენებული არ არის"</string> + <string name="abandoned_promise_explanation" msgid="3990027586878167529">"ამ ხატულის აპი დაყენებული არ არის. შეგიძლიათ ამოშალოთ, ან მოიძიოთ აპი და ხელით მოახდინოთ მისი ინსტალაცია."</string> </resources> diff --git a/res/values-kk-rKZ/strings.xml b/res/values-kk-rKZ/strings.xml new file mode 100644 index 000000000..288129ace --- /dev/null +++ b/res/values-kk-rKZ/strings.xml @@ -0,0 +1,122 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +* Copyright (C) 2008 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. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="application_name" msgid="5181331383435256801">"Launcher3"</string> + <string name="home" msgid="7658288663002113681">"Негізгі"</string> + <string name="uid_name" msgid="7820867637514617527">"Android Core қолданбалары"</string> + <string name="folder_name" msgid="7371454440695724752"></string> + <string name="activity_not_found" msgid="8071924732094499514">"Қолданба орнатылмаған."</string> + <!-- no translation found for safemode_shortcut_error (9160126848219158407) --> + <skip /> + <string name="widgets_tab_label" msgid="2921133187116603919">"Виджеттер"</string> + <string name="widget_adder" msgid="3201040140710381657">"Виджеттер"</string> + <string name="toggle_weight_watcher" msgid="5645299835184636119">"Жадты көрсету"</string> + <string name="long_press_widget_to_add" msgid="7699152356777458215">"Виджетті таңдау үшін түртіп, мықтап ұстаңыз."</string> + <string name="market" msgid="2619650989819296998">"Дүкен"</string> + <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string> + <string name="external_drop_widget_error" msgid="3165821058322217155">"Элементті осы Негізгі Экранға тастау орындалмады."</string> + <string name="external_drop_widget_pick_title" msgid="3486317258037690630">"Жасақтау үшін виджет таңдау"</string> + <string name="rename_folder_label" msgid="3727762225964550653">"Қалта атауы"</string> + <string name="rename_folder_title" msgid="3771389277707820891">"Қалтаның атауын өзгерту"</string> + <string name="rename_action" msgid="5559600076028658757">"Жарайды"</string> + <string name="cancel_action" msgid="7009134900002915310">"Өшіру"</string> + <string name="menu_item_add_item" msgid="1264911265836810421">"Негізгі экранға қосу"</string> + <string name="group_applications" msgid="3797214114206693605">"Қолданбалар"</string> + <string name="group_shortcuts" msgid="6012256992764410535">"Төте пернелер"</string> + <string name="group_widgets" msgid="1569030723286851002">"Виджеттер"</string> + <string name="completely_out_of_space" msgid="6106288382070760318">"Негізгі экранда орын жоқ."</string> + <string name="out_of_space" msgid="4691004494942118364">"Бұл Негізгі экранда орын қалмады."</string> + <string name="hotseat_out_of_space" msgid="7448809638125333693">"Қалаулылар науасында орын қалмады"</string> + <string name="invalid_hotseat_item" msgid="5779907847267573691">"Бұл виджет Қалаулылар науасы үшін тым үлкен"</string> + <string name="shortcut_installed" msgid="1701742129426969556">"\"<xliff:g id="NAME">%s</xliff:g>\" төте пернесі жасақталды."</string> + <string name="shortcut_uninstalled" msgid="8176767991305701821">"\"<xliff:g id="NAME">%s</xliff:g>\" төте пернесі алынды."</string> + <string name="shortcut_duplicate" msgid="9167217446062498127">"\"<xliff:g id="NAME">%s</xliff:g>\" төте пернесі бұрыннан бар."</string> + <string name="title_select_shortcut" msgid="6680642571148153868">"Төте перне таңдау"</string> + <string name="title_select_application" msgid="3280812711670683644">"Қолданба таңдау"</string> + <string name="all_apps_button_label" msgid="9110807029020582876">"Қолданбалар"</string> + <string name="all_apps_home_button_label" msgid="252062713717058851">"Негізгі"</string> + <string name="delete_zone_label_workspace" msgid="4009607676751398685">"Алып тастау"</string> + <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"Алмау"</string> + <string name="delete_target_label" msgid="1822697352535677073">"Алып тастау"</string> + <string name="delete_target_uninstall_label" msgid="5100785476250872595">"Алмау"</string> + <string name="info_target_label" msgid="8053346143994679532">"Қолданба ақпары"</string> + <string name="accessibility_search_button" msgid="1628520399424565142">"Іздеу"</string> + <string name="accessibility_voice_search_button" msgid="4637324840434406584">"Дауыс арқылы іздеу"</string> + <string name="accessibility_all_apps_button" msgid="2603132375383800483">"Қолданбалар"</string> + <string name="accessibility_delete_button" msgid="6466114477993744621">"Алып тастау"</string> + <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"Жаңартуды алмау"</string> + <string name="cab_menu_delete_app" msgid="7435191475867183689">"Қолданбаны алып тастау"</string> + <string name="cab_menu_app_info" msgid="8593722221450362342">"Қолданба туралы толығырақ"</string> + <string name="cab_app_selection_text" msgid="374688303047985416">"1 қолданба таңдалған"</string> + <string name="cab_widget_selection_text" msgid="1833458597831541241">"1 виджет таңдалған"</string> + <string name="cab_folder_selection_text" msgid="7999992513806132118">"1 қалта таңдалған"</string> + <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"1 төте перне таңдалған"</string> + <string name="permlab_install_shortcut" msgid="5632423390354674437">"төте пернелерді орнату"</string> + <string name="permdesc_install_shortcut" msgid="923466509822011139">"Қолданбаға пайдаланушының қатысуынсыз төте пернелерді қосу мүмкіндігін береді."</string> + <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"төте пернелерді алып тастау"</string> + <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"Қолданбаға пайдаланушының қатысуынсыз төте пернелерді алу мүмкіндігін береді."</string> + <string name="permlab_read_settings" msgid="1941457408239617576">"Негізгі экрандағы параметрлер мен төте пернелерді оқу"</string> + <string name="permdesc_read_settings" msgid="5833423719057558387">"Қолданбаға Негізгі экрандағы параметрлер мен төте пернелерді оқу мүмкіндігін береді."</string> + <string name="permlab_write_settings" msgid="3574213698004620587">"Негізгі экран параметрлері мен төте пернелерін жазу"</string> + <string name="permdesc_write_settings" msgid="5440712911516509985">"Қолданбаға Негізгі экрандағы параметрлер мен төте пернелерді өзгерту мүмкіндігін береді."</string> + <string name="gadget_error_text" msgid="6081085226050792095">"Виджетті жүктеу барысында мәселе орын алды"</string> + <string name="uninstall_system_app_text" msgid="4172046090762920660">"Бұл жүйе қолданбасы, сондықтан оны алу мүмкін емес."</string> + <string name="dream_name" msgid="1530253749244328964">"Rocket Launcher"</string> + <string name="folder_hint_text" msgid="6617836969016293992">"Атауы жоқ қалта"</string> + <string name="workspace_description_format" msgid="2950174241104043327">"%1$d негізгі экран"</string> + <string name="default_scroll_format" msgid="7475544710230993317">"%1$d бет, барлығы %2$d"</string> + <string name="workspace_scroll_format" msgid="8458889198184077399">"%1$d негізгі экран, барлығы %2$d"</string> + <string name="apps_customize_apps_scroll_format" msgid="370005296147130238">"%1$d қолданба беті, барлығы %2$d"</string> + <string name="apps_customize_widgets_scroll_format" msgid="3106209519974971521">"%1$d виджет беті, барлығы %2$d"</string> + <string name="first_run_cling_title" msgid="2459738000155917941">"Қош келдіңіз"</string> + <string name="first_run_cling_description" msgid="6447072552696253358">"Өзіңізді ыңғайлы сезініңіз."</string> + <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string> + <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string> + <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"Қолданбалар мен қалталар үшін көбірек экрандар жасау"</string> + <string name="migration_cling_title" msgid="9181776667882933767">"Қолданба таңбаларын көшіру"</string> + <string name="migration_cling_description" msgid="2752413805582227644">"Бұрынғы негізгі экрандарыңыздағы таңбалар мен қалталар импортталсын ба?"</string> + <string name="migration_cling_copy_apps" msgid="946331230090919440">"ТАҢБАЛАРДЫ КӨШІРУ"</string> + <string name="migration_cling_use_default" msgid="2626475813981258626">"ЖАҢАДАН БАСТАУ"</string> + <string name="workspace_cling_title" msgid="5626202359865825661">"Кеңістікті реттеу"</string> + <string name="workspace_cling_move_item" msgid="528201129978005352">"Артқы фонды, виджеттерді және параметрлерді басқару үшін артқы шебін түртіп, мықтап ұстаңыз."</string> + <string name="folder_cling_title" msgid="3894908818693254164">"Міне, қалта."</string> + <string name="folder_cling_create_folder" msgid="6158215559475836131">"Осы сияқты қалта жасау үшін, қолданбаны түртіп, мықтап ұстаңыз, одан кейін екіншісінің үстінен жылжытыңыз."</string> + <string name="cling_dismiss" msgid="8962359497601507581">"Жарайды"</string> + <string name="folder_opened" msgid="94695026776264709">"Қалта ашылды, <xliff:g id="WIDTH">%1$d</xliff:g> және <xliff:g id="HEIGHT">%2$d</xliff:g>"</string> + <string name="folder_tap_to_close" msgid="1884479294466410023">"Қалтаны жабу үшін түртіңіз"</string> + <string name="folder_tap_to_rename" msgid="9191075570492871147">"Өзгертілген атауын сақтау үшін түртіңіз"</string> + <string name="folder_closed" msgid="4100806530910930934">"Қалта жабылды"</string> + <string name="folder_renamed" msgid="1794088362165669656">"Қалта атауы <xliff:g id="NAME">%1$s</xliff:g> болып өзгертілді"</string> + <string name="folder_name_format" msgid="6629239338071103179">"Қалта: <xliff:g id="NAME">%1$s</xliff:g>"</string> + <string name="widget_button_text" msgid="2880537293434387943">"Виджеттер"</string> + <string name="wallpaper_button_text" msgid="8404103075899945851">"Артқы фондар"</string> + <string name="settings_button_text" msgid="8119458837558863227">"Параметрлер"</string> + <string name="package_state_enqueued" msgid="6227252464303085641">"Күтілуде"</string> + <string name="package_state_downloading" msgid="4088770468458724721">"Жүктелуде"</string> + <string name="package_state_installing" msgid="7588193972189849870">"Орнатылуда"</string> + <string name="package_state_unknown" msgid="7592128424511031410">"Белгісіз"</string> + <string name="package_state_error" msgid="7672093962724223588">"Қалп. кел-меді"</string> + <string name="abandoned_clean_all" msgid="5256770727689657618">"Барлығын алып тастау"</string> + <string name="abandoned_clean_this" msgid="7610119707847920412">"Алып тастау"</string> + <string name="abandoned_search" msgid="891119232568284442">"Іздеу"</string> + <string name="abandoned_promises_title" msgid="7096178467971716750">"Бұл қолданба орнатылмаған"</string> + <string name="abandoned_promise_explanation" msgid="3990027586878167529">"Осы белгіше үшін қолданба орнатылмаған. Оны жоюға болады немесе қолданбаны іздеп, қолмен орнатуға болады."</string> +</resources> diff --git a/res/values-km-rKH/strings.xml b/res/values-km-rKH/strings.xml index 8bf26c221..bcd606000 100644 --- a/res/values-km-rKH/strings.xml +++ b/res/values-km-rKH/strings.xml @@ -24,6 +24,7 @@ <string name="uid_name" msgid="7820867637514617527">"កម្មវិធីសំខាន់ៗរបស់ Android"</string> <string name="folder_name" msgid="7371454440695724752"></string> <string name="activity_not_found" msgid="8071924732094499514">"មិនបានដំឡើងកម្មវិធី។"</string> + <string name="safemode_shortcut_error" msgid="9160126848219158407">"បានបិទកម្មវិធីដែលបានទាញយកក្នុងរបៀបសុវត្ថិភាព"</string> <string name="widgets_tab_label" msgid="2921133187116603919">"ធាតុក្រាហ្វិក"</string> <string name="widget_adder" msgid="3201040140710381657">"ធាតុក្រាហ្វិក"</string> <string name="toggle_weight_watcher" msgid="5645299835184636119">"បង្ហាញ Mem"</string> @@ -76,6 +77,7 @@ <string name="permlab_write_settings" msgid="3574213698004620587">"សរសេរការកំណត់ និងផ្លូវកាត់លើអេក្រង់ដើម"</string> <string name="permdesc_write_settings" msgid="5440712911516509985">"អនុញ្ញាតឲ្យកម្មវិធីប្ដូរការកំណត់ និងផ្លូវកាត់ក្នុងអេក្រង់ដើម។"</string> <string name="gadget_error_text" msgid="6081085226050792095">"បញ្ហាក្នុងការផ្ទុកធាតុក្រាហ្វិក"</string> + <string name="gadget_setup_text" msgid="8274003207686040488">"រៀបចំ"</string> <string name="uninstall_system_app_text" msgid="4172046090762920660">"នេះជាកម្មវិធីប្រព័ន្ធ មិនអាចលុបបានទេ។"</string> <string name="dream_name" msgid="1530253749244328964">"កម្មវិធីចាប់ផ្ដើមរ៉ូកែត"</string> <string name="folder_hint_text" msgid="6617836969016293992">"ថតគ្មានឈ្មោះ"</string> @@ -95,6 +97,9 @@ <string name="migration_cling_use_default" msgid="2626475813981258626">"ចាប់ផ្ដើមធ្វើឲ្យស្រស់"</string> <string name="workspace_cling_title" msgid="5626202359865825661">"រៀបចំចន្លោះរបស់អ្នក"</string> <string name="workspace_cling_move_item" msgid="528201129978005352">"ប៉ះ & សង្កត់លើផ្ទៃខាងក្រោម ដើម្បីគ្រប់គ្រងផ្ទាំងរូបភាព, ធាតុក្រាហ្វិក និងការកំណត់។"</string> + <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"ផ្ទាំងរូបភាព,ធាតុក្រាហ្វិក & ការកំណត់"</string> + <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"ប៉ះ & សង្កត់ផ្ទៃខាងក្រោយដើម្បីប្ដូរតាមតម្រូវការ"</string> + <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"យល់ហើយ"</string> <string name="folder_cling_title" msgid="3894908818693254164">"នេះជាថត"</string> <string name="folder_cling_create_folder" msgid="6158215559475836131">"ដើម្បីបង្កើតមួយដូចនេះ ប៉ះ & សង្កត់លើកម្មវិធី បន្ទាប់មកផ្លាស់ទីវាទៅលើធាតុមួយផ្សេងទៀត។"</string> <string name="cling_dismiss" msgid="8962359497601507581">"យល់ព្រម"</string> @@ -107,4 +112,14 @@ <string name="widget_button_text" msgid="2880537293434387943">"ធាតុក្រាហ្វិក"</string> <string name="wallpaper_button_text" msgid="8404103075899945851">"ផ្ទាំងរូបភាព"</string> <string name="settings_button_text" msgid="8119458837558863227">"ការកំណត់"</string> + <string name="package_state_enqueued" msgid="6227252464303085641">"រង់ចាំ"</string> + <string name="package_state_downloading" msgid="4088770468458724721">"ទាញយក"</string> + <string name="package_state_installing" msgid="7588193972189849870">"ដំឡើង"</string> + <string name="package_state_unknown" msgid="7592128424511031410">"មិនស្គាល់"</string> + <string name="package_state_error" msgid="7672093962724223588">"មិនបានស្តារ"</string> + <string name="abandoned_clean_all" msgid="5256770727689657618">"លុបចេញទាំងអស់"</string> + <string name="abandoned_clean_this" msgid="7610119707847920412">"លុបចេញ"</string> + <string name="abandoned_search" msgid="891119232568284442">"ស្វែងរក"</string> + <string name="abandoned_promises_title" msgid="7096178467971716750">"មិនបានដំឡើងកម្មវិធីនេះ"</string> + <string name="abandoned_promise_explanation" msgid="3990027586878167529">"មិនបានដំឡើងកម្មវិធីសម្រាប់រូបតំណាងនេះ។ អ្នកអាចលុបវា ឬស្វែងរកកម្មវិធី និងដំឡើងវាដោយដៃ។"</string> </resources> diff --git a/res/values-kn-rIN/strings.xml b/res/values-kn-rIN/strings.xml new file mode 100644 index 000000000..e84ece03c --- /dev/null +++ b/res/values-kn-rIN/strings.xml @@ -0,0 +1,121 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +* Copyright (C) 2008 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. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="application_name" msgid="5181331383435256801">"ಲಾಂಚರ್3"</string> + <string name="home" msgid="7658288663002113681">"ಮುಖಪುಟ"</string> + <string name="uid_name" msgid="7820867637514617527">"Android Core ಅಪ್ಲಿಕೇಶನ್ಗಳು"</string> + <string name="folder_name" msgid="7371454440695724752"></string> + <string name="activity_not_found" msgid="8071924732094499514">"ಅಪ್ಲಿಕೇಶನ್ ಅನ್ನು ಸ್ಥಾಪಿಸಲಾಗಿಲ್ಲ"</string> + <string name="safemode_shortcut_error" msgid="9160126848219158407">"ಡೌನ್ಲೋಡ್ ಮಾಡಲಾದ ಅಪ್ಲಿಕೇಶನ್ ಅನ್ನು ಸುರಕ್ಷಿತ ಮೋಡ್ನಲ್ಲಿ ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ"</string> + <string name="widgets_tab_label" msgid="2921133187116603919">"ವಿಜೆಟ್ಗಳು"</string> + <string name="widget_adder" msgid="3201040140710381657">"ವಿಜೆಟ್ಗಳು"</string> + <string name="toggle_weight_watcher" msgid="5645299835184636119">"ಸ್ಮರಣೆ ತೋರಿಸು"</string> + <string name="long_press_widget_to_add" msgid="7699152356777458215">"ವಿಜೆಟ್ ಅನ್ನು ಆರಿಸಿಕೊಳ್ಳಲು ಸ್ಪರ್ಶಿಸಿ & ಹಿಡಿದುಕೊಳ್ಳಿ."</string> + <string name="market" msgid="2619650989819296998">"ಶಾಪ್"</string> + <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string> + <string name="external_drop_widget_error" msgid="3165821058322217155">"ಈ ಮುಖಪುಟದ ಪರದೆಯಲ್ಲಿ ಐಟಂ ಅನ್ನು ಬಿಡಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ."</string> + <string name="external_drop_widget_pick_title" msgid="3486317258037690630">"ರಚಿಸಲು ವಿಜೆಟ್ ಆಯ್ಕೆಮಾಡಿ"</string> + <string name="rename_folder_label" msgid="3727762225964550653">"ಫೋಲ್ಡರ್ ಹೆಸರು"</string> + <string name="rename_folder_title" msgid="3771389277707820891">"ಫೋಲ್ಡರ್ ಅನ್ನು ಮರುಹೆಸರಿಸಿ"</string> + <string name="rename_action" msgid="5559600076028658757">"ಸರಿ"</string> + <string name="cancel_action" msgid="7009134900002915310">"ರದ್ದುಮಾಡು"</string> + <string name="menu_item_add_item" msgid="1264911265836810421">"ಮುಖಪುಟಕ್ಕೆ ಸೇರಿಸು"</string> + <string name="group_applications" msgid="3797214114206693605">"ಅಪ್ಲಿಕೇಶನ್ಗಳು"</string> + <string name="group_shortcuts" msgid="6012256992764410535">"ಶಾರ್ಟ್ಕಟ್ಗಳು"</string> + <string name="group_widgets" msgid="1569030723286851002">"ವಿಜೆಟ್ಗಳು"</string> + <string name="completely_out_of_space" msgid="6106288382070760318">"ನಿಮ್ಮ ಮುಖಪುಟದ ಪರದೆಗಳಲ್ಲಿ ಯಾವುದೇ ಸ್ಥಳಾವಕಾಶವಿಲ್ಲ"</string> + <string name="out_of_space" msgid="4691004494942118364">"ಈ ಮುಖಪುಟದ ಪರದೆಯಲ್ಲಿ ಹೆಚ್ಚು ಸ್ಥಳಾವಕಾಶವಿಲ್ಲ."</string> + <string name="hotseat_out_of_space" msgid="7448809638125333693">"ಮೆಚ್ಚಿನವುಗಳ ಟ್ರೇನಲ್ಲಿ ಹೆಚ್ಚಿನ ಸ್ಥಳಾವಕಾಶವಿಲ್ಲ"</string> + <string name="invalid_hotseat_item" msgid="5779907847267573691">"ಮೆಚ್ಚಿನವುಗಳ ಟ್ರೇಗೆ ಈ ವಿಜೆಟ್ ತುಂಬಾ ದೊಡ್ಡದಾಗಿದೆ"</string> + <string name="shortcut_installed" msgid="1701742129426969556">"ಶಾರ್ಟ್ಕಟ್ \"<xliff:g id="NAME">%s</xliff:g>\" ಅನ್ನು ರಚಿಸಲಾಗಿದೆ."</string> + <string name="shortcut_uninstalled" msgid="8176767991305701821">"ಶಾರ್ಟ್ಕಟ್ \"<xliff:g id="NAME">%s</xliff:g>\" ಅನ್ನು ತೆಗೆದುಹಾಕಲಾಗಿದೆ."</string> + <string name="shortcut_duplicate" msgid="9167217446062498127">"ಶಾರ್ಟ್ಕಟ್ \"<xliff:g id="NAME">%s</xliff:g>\" ಈಗಾಗಲೇ ಅಸ್ತಿತ್ವದಲ್ಲಿದೆ."</string> + <string name="title_select_shortcut" msgid="6680642571148153868">"ಶಾರ್ಟ್ಕಟ್ ಆರಿಸಿ"</string> + <string name="title_select_application" msgid="3280812711670683644">"ಅಪ್ಲಿಕೇಶನ್ ಆಯ್ಕೆಮಾಡಿ"</string> + <string name="all_apps_button_label" msgid="9110807029020582876">"ಅಪ್ಲಿಕೇಶನ್ಗಳು"</string> + <string name="all_apps_home_button_label" msgid="252062713717058851">"ಮುಖಪುಟ"</string> + <string name="delete_zone_label_workspace" msgid="4009607676751398685">"ತೆಗೆದುಹಾಕು"</string> + <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"ಅಸ್ಥಾಪಿಸು"</string> + <string name="delete_target_label" msgid="1822697352535677073">"ತೆಗೆದುಹಾಕು"</string> + <string name="delete_target_uninstall_label" msgid="5100785476250872595">"ಅಸ್ಥಾಪಿಸು"</string> + <string name="info_target_label" msgid="8053346143994679532">"ಅಪ್ಲಿಕೇಶನ್ ಮಾಹಿತಿ"</string> + <string name="accessibility_search_button" msgid="1628520399424565142">"ಹುಡುಕು"</string> + <string name="accessibility_voice_search_button" msgid="4637324840434406584">"ಧ್ವನಿ ಹುಡುಕಾಟ"</string> + <string name="accessibility_all_apps_button" msgid="2603132375383800483">"ಅಪ್ಲಿಕೇಶನ್ಗಳು"</string> + <string name="accessibility_delete_button" msgid="6466114477993744621">"ತೆಗೆದುಹಾಕು"</string> + <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"ನವೀಕರಣವನ್ನು ಅಸ್ಥಾಪಿಸು"</string> + <string name="cab_menu_delete_app" msgid="7435191475867183689">"ಅಪ್ಲಿಕೇಶನ್ ಅಸ್ಥಾಪಿಸು"</string> + <string name="cab_menu_app_info" msgid="8593722221450362342">"ಅಪ್ಲಿಕೇಶನ್ ವಿವರಗಳು"</string> + <string name="cab_app_selection_text" msgid="374688303047985416">"1 ಅಪ್ಲಿಕೇಶನ್ ಅನ್ನು ಆಯ್ಕೆ ಮಾಡಲಾಗಿದೆ"</string> + <string name="cab_widget_selection_text" msgid="1833458597831541241">"1 ವಿಜೆಟ್ ಆಯ್ಕೆಮಾಡಲಾಗಿದೆ"</string> + <string name="cab_folder_selection_text" msgid="7999992513806132118">"1 ಫೋಲ್ಡರ್ ಅನ್ನು ಆಯ್ಕೆ ಮಾಡಲಾಗಿದೆ"</string> + <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"1 ಶಾರ್ಟ್ಕಟ್ ಆಯ್ಕೆ ಮಾಡಲಾಗಿದೆ"</string> + <string name="permlab_install_shortcut" msgid="5632423390354674437">"ಶಾರ್ಟ್ಕಟ್ಗಳನ್ನು ಸ್ಥಾಪಿಸಿ"</string> + <string name="permdesc_install_shortcut" msgid="923466509822011139">"ಬಳಕೆದಾರರ ಹಸ್ತಕ್ಷೇಪವಿಲ್ಲದೆ ಶಾರ್ಟ್ಕಟ್ಗಳನ್ನು ಸೇರಿಸಲು ಅಪ್ಲಿಕೇಶನ್ಗೆ ಅನುಮತಿಸುತ್ತದೆ."</string> + <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"ಶಾರ್ಟ್ಕಟ್ಗಳನ್ನು ಅಸ್ಥಾಪಿಸಿ"</string> + <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"ಬಳಕೆದಾರರ ಹಸ್ತಕ್ಷೇಪವಿಲ್ಲದೆ ಶಾರ್ಟ್ಕಟ್ಗಳನ್ನು ತೆಗೆದುಹಾಕಲು ಅಪ್ಲಿಕೇಶನ್ಗೆ ಅನುಮತಿ ನೀಡುತ್ತದೆ."</string> + <string name="permlab_read_settings" msgid="1941457408239617576">"ಮುಖಪುಟದ ಸೆಟ್ಟಿಂಗ್ಗಳು ಮತ್ತು ಶಾರ್ಟ್ಕಟ್ಗಳನ್ನು ಓದಿ"</string> + <string name="permdesc_read_settings" msgid="5833423719057558387">"ಮುಖಪುಟದಲ್ಲಿ ಸೆಟ್ಟಿಂಗ್ಗಳು ಮತ್ತು ಶಾರ್ಟ್ಕಟ್ಗಳನ್ನು ಓದಲು ಅಪ್ಲಿಕೇಶನ್ಗೆ ಅನುಮತಿ ನೀಡುತ್ತದೆ."</string> + <string name="permlab_write_settings" msgid="3574213698004620587">"ಮುಖಪುಟದ ಸೆಟ್ಟಿಂಗ್ಗಳು ಮತ್ತು ಶಾರ್ಟ್ಕಟ್ಗಳನ್ನು ಬರೆಯಿರಿ"</string> + <string name="permdesc_write_settings" msgid="5440712911516509985">"ಮುಖಪುಟದಲ್ಲಿ ಸೆಟ್ಟಿಂಗ್ಗಳು ಮತ್ತು ಶಾರ್ಟ್ಕಟ್ಗಳನ್ನು ಬದಲಾಯಿಸಲು ಅಪ್ಲಿಕೇಶನ್ಗೆ ಅನುಮತಿ ನೀಡುತ್ತದೆ."</string> + <string name="gadget_error_text" msgid="6081085226050792095">"ವಿಜೆಟ್ ಲೋಡ್ ಮಾಡುವಲ್ಲಿ ಸಮಸ್ಯೆ"</string> + <string name="uninstall_system_app_text" msgid="4172046090762920660">"ಇದೊಂದು ಅಪ್ಲಿಕೇಶನ್ ಆಗಿದೆ ಮತ್ತು ಅಸ್ಥಾಪಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ."</string> + <string name="dream_name" msgid="1530253749244328964">"ರಾಕೆಟ್ ಲಾಂಚರ್"</string> + <string name="folder_hint_text" msgid="6617836969016293992">"ಹೆಸರಿಲ್ಲದ ಫೋಲ್ಡರ್"</string> + <string name="workspace_description_format" msgid="2950174241104043327">"ಮುಖಪುಟದ ಪರದೆ %1$d"</string> + <string name="default_scroll_format" msgid="7475544710230993317">"%2$d ರಲ್ಲಿ %1$d ಪುಟ"</string> + <string name="workspace_scroll_format" msgid="8458889198184077399">"%2$d ರಲ್ಲಿ %1$d ಮುಖಪುಟದ ಪರದೆ"</string> + <string name="apps_customize_apps_scroll_format" msgid="370005296147130238">"%2$d ರಲ್ಲಿ %1$d ಅಪ್ಲಿಕೇಶನ್ ಪುಟ"</string> + <string name="apps_customize_widgets_scroll_format" msgid="3106209519974971521">"%2$d ರಲ್ಲಿ %1$d ವಿಜೆಟ್ಗಳ ಪುಟ"</string> + <string name="first_run_cling_title" msgid="2459738000155917941">"ಸುಸ್ವಾಗತ"</string> + <string name="first_run_cling_description" msgid="6447072552696253358">"ನಿಮ್ಮ ಮನೆಯಂತೆ ಭಾವಿಸಿ."</string> + <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string> + <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string> + <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"ಅಪ್ಲಿಕೇಶನ್ಗಳು ಮತ್ತು ಫೋಲ್ಡರ್ಗಳಿಗಾಗಿ ಇನ್ನಷ್ಟು ಪರದೆಗಳನ್ನು ರಚಿಸಿ"</string> + <string name="migration_cling_title" msgid="9181776667882933767">"ಅಪ್ಲಿಕೇಶನ್ ಐಕಾನ್ ನಕಲಿಸು"</string> + <string name="migration_cling_description" msgid="2752413805582227644">"ನಿಮ್ಮ ಹಳೆಯ ಮುಖಪುಟದ ಪರದೆಗಳಿಂದ ಐಕಾನ್ಗಳು ಮತ್ತು ಫೋಲ್ಡರ್ಗಳನ್ನು ಆಮದು ಮಾಡಿಕೊಳ್ಳುವುದೇ?"</string> + <string name="migration_cling_copy_apps" msgid="946331230090919440">"ಐಕಾನ್ಗಳನ್ನು ನಕಲಿಸು"</string> + <string name="migration_cling_use_default" msgid="2626475813981258626">"ಹೊಸದಾಗಿ ಪ್ರಾರಂಭಿಸು"</string> + <string name="workspace_cling_title" msgid="5626202359865825661">"ನಿಮ್ಮ ಸ್ಥಳವನ್ನು ವ್ಯವಸ್ಥಿತಗೊಳಿಸಿ"</string> + <string name="workspace_cling_move_item" msgid="528201129978005352">"ವಾಲ್ಪೇಪರ್, ವಿಜೆಟ್ಗಳು ಮತ್ತು ಸೆಟ್ಟಿಂಗ್ಗಳನ್ನು ನಿರ್ವಹಿಸಲು ಹಿನ್ನೆಲೆಯನ್ನು ಸ್ಪರ್ಶಿಸಿ & ಹಿಡಿದುಕೊಳ್ಳಿ."</string> + <string name="folder_cling_title" msgid="3894908818693254164">"ಇಲ್ಲೊಂದು ಫೋಲ್ಡರ್ ಇದೆ"</string> + <string name="folder_cling_create_folder" msgid="6158215559475836131">"ಈ ರೀತಿ ರಚಿಸಲು, ಸ್ಪರ್ಶಿಸಿ & ಆಪ್ ಹಿಡಿದುಕೊಂಡು ಮತ್ತೊಂದರ ಮೇಲೆ ಸರಿಸಿ."</string> + <string name="cling_dismiss" msgid="8962359497601507581">"ಸರಿ"</string> + <string name="folder_opened" msgid="94695026776264709">"ಫೋಲ್ಡರ್ ತೆರೆಯಲಾಗಿದೆ, <xliff:g id="WIDTH">%1$d</xliff:g> ಬೈ <xliff:g id="HEIGHT">%2$d</xliff:g>"</string> + <string name="folder_tap_to_close" msgid="1884479294466410023">"ಫೋಲ್ಡರ್ ಮುಚ್ಚಲು ಸ್ಪರ್ಶಿಸಿ"</string> + <string name="folder_tap_to_rename" msgid="9191075570492871147">"ಮರುಹೆಸರನ್ನು ಉಳಿಸಲು ಸ್ಪರ್ಶಿಸಿ"</string> + <string name="folder_closed" msgid="4100806530910930934">"ಫೋಲ್ಡರ್ ಮುಚ್ಚಿದೆ"</string> + <string name="folder_renamed" msgid="1794088362165669656">"ಫೋಲ್ಡರ್ ಅನ್ನು <xliff:g id="NAME">%1$s</xliff:g> ಗೆ ಮರುಹೆಸರಿಸಲಾಗಿದೆ"</string> + <string name="folder_name_format" msgid="6629239338071103179">"ಫೋಲ್ಡರ್: <xliff:g id="NAME">%1$s</xliff:g>"</string> + <string name="widget_button_text" msgid="2880537293434387943">"ವಿಜೆಟ್ಗಳು"</string> + <string name="wallpaper_button_text" msgid="8404103075899945851">"ವಾಲ್ಪೇಪರ್ಗಳು"</string> + <string name="settings_button_text" msgid="8119458837558863227">"ಸೆಟ್ಟಿಂಗ್ಗಳು"</string> + <string name="package_state_enqueued" msgid="6227252464303085641">"ನಿರೀಕ್ಷಿಸಲಾಗುತ್ತಿದೆ"</string> + <string name="package_state_downloading" msgid="4088770468458724721">"ಡೌನ್ಲೋಡ್ ಮಾಡಲಾಗುತ್ತಿದೆ"</string> + <string name="package_state_installing" msgid="7588193972189849870">"ಸ್ಥಾಪಿಸಲಾಗುತ್ತಿದೆ"</string> + <string name="package_state_unknown" msgid="7592128424511031410">"ಅಜ್ಞಾತ"</string> + <string name="package_state_error" msgid="7672093962724223588">"ಇನ್ನೂ ಪುನಃಸ್ಥಾಪಿಸಲಾಗಿಲ್ಲ"</string> + <string name="abandoned_clean_all" msgid="5256770727689657618">"ಎಲ್ಲವನ್ನೂ ತೆಗೆದುಹಾಕಿ"</string> + <string name="abandoned_clean_this" msgid="7610119707847920412">"ತೆಗೆದುಹಾಕಿ"</string> + <string name="abandoned_search" msgid="891119232568284442">"ಹುಡುಕು"</string> + <string name="abandoned_promises_title" msgid="7096178467971716750">"ಈ ಅಪ್ಲಿಕೇಶನ್ ಸ್ಥಾಪನೆಗೊಂಡಿಲ್ಲ"</string> + <string name="abandoned_promise_explanation" msgid="3990027586878167529">"ಈ ಐಕಾನ್ ಅಪ್ಲಿಕೇಶನ್ ಸ್ಥಾಪನೆಗೊಂಡಿಲ್ಲ. ನೀವು ಅದನ್ನು ತೆಗೆದುಹಾಕಬಹುದು ಅಥವಾ ಅಪ್ಲಿಕೇಶನ್ ಹುಡುಕಬಹುದು ಮತ್ತು ಹಸ್ತಚಾಲಿತವಾಗಿ ಅದನ್ನು ಸ್ಥಾಪಿಸಬಹುದು."</string> +</resources> diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml index dde4eb781..41c854ec3 100644 --- a/res/values-ko/strings.xml +++ b/res/values-ko/strings.xml @@ -24,6 +24,7 @@ <string name="uid_name" msgid="7820867637514617527">"Android 핵심 앱"</string> <string name="folder_name" msgid="7371454440695724752"></string> <string name="activity_not_found" msgid="8071924732094499514">"앱이 설치되지 않았습니다."</string> + <string name="safemode_shortcut_error" msgid="9160126848219158407">"다운로드한 앱은 안전 모드에서 사용할 수 없습니다."</string> <string name="widgets_tab_label" msgid="2921133187116603919">"위젯"</string> <string name="widget_adder" msgid="3201040140710381657">"위젯"</string> <string name="toggle_weight_watcher" msgid="5645299835184636119">"메모리 표시"</string> @@ -76,6 +77,7 @@ <string name="permlab_write_settings" msgid="3574213698004620587">"홈 설정 및 바로가기 쓰기"</string> <string name="permdesc_write_settings" msgid="5440712911516509985">"앱이 홈에 있는 설정 및 바로가기를 변경할 수 있도록 합니다."</string> <string name="gadget_error_text" msgid="6081085226050792095">"위젯을 로드하는 중 문제가 발생했습니다."</string> + <string name="gadget_setup_text" msgid="8274003207686040488">"설정"</string> <string name="uninstall_system_app_text" msgid="4172046090762920660">"시스템 앱은 제거할 수 없습니다."</string> <string name="dream_name" msgid="1530253749244328964">"로켓 실행기"</string> <string name="folder_hint_text" msgid="6617836969016293992">"이름이 없는 폴더"</string> @@ -95,6 +97,9 @@ <string name="migration_cling_use_default" msgid="2626475813981258626">"새로 시작"</string> <string name="workspace_cling_title" msgid="5626202359865825661">"공간 관리하기"</string> <string name="workspace_cling_move_item" msgid="528201129978005352">"배경화면, 위젯, 설정을 관리하려면 백그라운드를 길게 터치합니다."</string> + <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"배경화면, 위젯, 설정"</string> + <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"백그라운드를 길게 터치하여 맞춤설정합니다."</string> + <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"확인"</string> <string name="folder_cling_title" msgid="3894908818693254164">"폴더"</string> <string name="folder_cling_create_folder" msgid="6158215559475836131">"폴더를 만들려면 앱을 길게 터치한 다음 다른 앱 위에 올려 놓으세요."</string> <string name="cling_dismiss" msgid="8962359497601507581">"확인"</string> @@ -107,4 +112,14 @@ <string name="widget_button_text" msgid="2880537293434387943">"위젯"</string> <string name="wallpaper_button_text" msgid="8404103075899945851">"배경화면"</string> <string name="settings_button_text" msgid="8119458837558863227">"설정"</string> + <string name="package_state_enqueued" msgid="6227252464303085641">"대기 중"</string> + <string name="package_state_downloading" msgid="4088770468458724721">"다운로드 중"</string> + <string name="package_state_installing" msgid="7588193972189849870">"설치 중"</string> + <string name="package_state_unknown" msgid="7592128424511031410">"알 수 없음"</string> + <string name="package_state_error" msgid="7672093962724223588">"복원되지 않음"</string> + <string name="abandoned_clean_all" msgid="5256770727689657618">"모두 삭제"</string> + <string name="abandoned_clean_this" msgid="7610119707847920412">"삭제"</string> + <string name="abandoned_search" msgid="891119232568284442">"검색"</string> + <string name="abandoned_promises_title" msgid="7096178467971716750">"이 앱이 설치되어 있지 않음"</string> + <string name="abandoned_promise_explanation" msgid="3990027586878167529">"이 아이콘의 앱이 설치되어 있지 않습니다. 아이콘을 삭제하거나 앱을 검색하여 수동으로 설치하세요."</string> </resources> diff --git a/res/values-ky-rKG/strings.xml b/res/values-ky-rKG/strings.xml new file mode 100644 index 000000000..5b50555ae --- /dev/null +++ b/res/values-ky-rKG/strings.xml @@ -0,0 +1,122 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +* Copyright (C) 2008 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. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="application_name" msgid="5181331383435256801">"Launcher3"</string> + <string name="home" msgid="7658288663002113681">"Үйгө"</string> + <string name="uid_name" msgid="7820867637514617527">"Android Core колдонмолору"</string> + <string name="folder_name" msgid="7371454440695724752"></string> + <string name="activity_not_found" msgid="8071924732094499514">"Колдонмо орнотулган эмес."</string> + <!-- no translation found for safemode_shortcut_error (9160126848219158407) --> + <skip /> + <string name="widgets_tab_label" msgid="2921133187116603919">"Виджеттер"</string> + <string name="widget_adder" msgid="3201040140710381657">"Виджеттер"</string> + <string name="toggle_weight_watcher" msgid="5645299835184636119">"Мемди көргөзүү"</string> + <string name="long_press_widget_to_add" msgid="7699152356777458215">"Виджетти тандаш үчүн, басып туруңуз"</string> + <string name="market" msgid="2619650989819296998">"Дүкөн"</string> + <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string> + <string name="external_drop_widget_error" msgid="3165821058322217155">"Муну бул Үй экранына ыргытуу мүмкүн эмес."</string> + <string name="external_drop_widget_pick_title" msgid="3486317258037690630">"Түзүлүүчү виджетти тандаңыз"</string> + <string name="rename_folder_label" msgid="3727762225964550653">"Фолдердин аты"</string> + <string name="rename_folder_title" msgid="3771389277707820891">"Фолдердин атын өзгөртүү"</string> + <string name="rename_action" msgid="5559600076028658757">"OK"</string> + <string name="cancel_action" msgid="7009134900002915310">"Жокко чыгаруу"</string> + <string name="menu_item_add_item" msgid="1264911265836810421">"Үй экранына кошуу"</string> + <string name="group_applications" msgid="3797214114206693605">"Колдонмолор"</string> + <string name="group_shortcuts" msgid="6012256992764410535">"Тез чакырмалар"</string> + <string name="group_widgets" msgid="1569030723286851002">"Виджеттер"</string> + <string name="completely_out_of_space" msgid="6106288382070760318">"Үй экрандарыңызда бош орун калган жок."</string> + <string name="out_of_space" msgid="4691004494942118364">"Бул Үй экранында бош орун жок."</string> + <string name="hotseat_out_of_space" msgid="7448809638125333693">"Тандамалдар тайпасында орун калган жок"</string> + <string name="invalid_hotseat_item" msgid="5779907847267573691">"Бул виджет Тандамалдар үчүн өтө чоң"</string> + <string name="shortcut_installed" msgid="1701742129426969556">"\"<xliff:g id="NAME">%s</xliff:g>\" тез чакырмасы түзүлдү."</string> + <string name="shortcut_uninstalled" msgid="8176767991305701821">"\"<xliff:g id="NAME">%s</xliff:g>\" тез чакырмасы алынып салынды."</string> + <string name="shortcut_duplicate" msgid="9167217446062498127">"\"<xliff:g id="NAME">%s</xliff:g>\" тез чакырмасы бар."</string> + <string name="title_select_shortcut" msgid="6680642571148153868">"Тез чакырма тандоо"</string> + <string name="title_select_application" msgid="3280812711670683644">"Колдонмо тандоо"</string> + <string name="all_apps_button_label" msgid="9110807029020582876">"Колдонмолор"</string> + <string name="all_apps_home_button_label" msgid="252062713717058851">"Үйгө"</string> + <string name="delete_zone_label_workspace" msgid="4009607676751398685">"Алып салуу"</string> + <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"Чечип салуу"</string> + <string name="delete_target_label" msgid="1822697352535677073">"Алып салуу"</string> + <string name="delete_target_uninstall_label" msgid="5100785476250872595">"Чечип салуу"</string> + <string name="info_target_label" msgid="8053346143994679532">"Колдонмо тууралуу"</string> + <string name="accessibility_search_button" msgid="1628520399424565142">"Издөө"</string> + <string name="accessibility_voice_search_button" msgid="4637324840434406584">"Үн менен издөө"</string> + <string name="accessibility_all_apps_button" msgid="2603132375383800483">"Колдонмолор"</string> + <string name="accessibility_delete_button" msgid="6466114477993744621">"Алып салуу"</string> + <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"Жаңыртууну чечип салуу"</string> + <string name="cab_menu_delete_app" msgid="7435191475867183689">"Колдонмону чечип салуу"</string> + <string name="cab_menu_app_info" msgid="8593722221450362342">"Колдонмонун кеңири маалыматтары"</string> + <string name="cab_app_selection_text" msgid="374688303047985416">"1 колдонмо тандалды"</string> + <string name="cab_widget_selection_text" msgid="1833458597831541241">"1 виджет тандалды"</string> + <string name="cab_folder_selection_text" msgid="7999992513806132118">"1 фолдер тандалды"</string> + <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"1 тез чакырма тандалды"</string> + <string name="permlab_install_shortcut" msgid="5632423390354674437">"тез чакырмаларды орнотуу"</string> + <string name="permdesc_install_shortcut" msgid="923466509822011139">"Колдонмого колдонуучуга кайрылбастан тез чакырма кошууга уруксат берет."</string> + <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"тез чакырмаларды жок кылуу"</string> + <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"Колдонмого колдонуучуга кайрылбастан тез чакырмаларды жок кылууга уруксат берет."</string> + <string name="permlab_read_settings" msgid="1941457408239617576">"Үйдүн тууралоолорун жана тез чакырмаларын окуу"</string> + <string name="permdesc_read_settings" msgid="5833423719057558387">"Колдонмого Үйдүн тууралоолорун жана тез чакырмаларын окууга уруксат берет."</string> + <string name="permlab_write_settings" msgid="3574213698004620587">"Үйдүн тууралоолорун жана тез чакырмаларын жазуу"</string> + <string name="permdesc_write_settings" msgid="5440712911516509985">"Колдонмого Үйдүн тууралоолорун жана тез чакырмаларын өзгөртүүгө уруксат берет."</string> + <string name="gadget_error_text" msgid="6081085226050792095">"Виджетти жүктөөдө маселе бар"</string> + <string name="uninstall_system_app_text" msgid="4172046090762920660">"Бул системдик колдонмо жана аны чечкенге болбойт."</string> + <string name="dream_name" msgid="1530253749244328964">"Rocket Launcher"</string> + <string name="folder_hint_text" msgid="6617836969016293992">"Аты жок фолдер"</string> + <string name="workspace_description_format" msgid="2950174241104043327">"Үй экраны %1$d"</string> + <string name="default_scroll_format" msgid="7475544710230993317">"%2$d ичинен %1$d барак"</string> + <string name="workspace_scroll_format" msgid="8458889198184077399">"Үй экраны %2$d ичинен %1$d"</string> + <string name="apps_customize_apps_scroll_format" msgid="370005296147130238">"Колдонмолор барагы %2$d ичинен %1$d"</string> + <string name="apps_customize_widgets_scroll_format" msgid="3106209519974971521">"Виджеттер барагы %2$d ичинен %1$d"</string> + <string name="first_run_cling_title" msgid="2459738000155917941">"Кош келиңиз"</string> + <string name="first_run_cling_description" msgid="6447072552696253358">"Өзүңүздү үйүңүздөгүдөй эркин сезиңиз."</string> + <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string> + <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string> + <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"Колдонмолор жана фолдерлер үчүн кошумча экрандарды түзүңүз"</string> + <string name="migration_cling_title" msgid="9181776667882933767">"Колдонмоңуздун сүрөтчөлөрүн көчүрүү"</string> + <string name="migration_cling_description" msgid="2752413805582227644">"Эски үй экрандарыңыздан сүрөтчөлөр жана фолдерлер импорттолсунбу?"</string> + <string name="migration_cling_copy_apps" msgid="946331230090919440">"СҮРӨТЧӨЛӨРДҮ КӨЧҮРҮҮ"</string> + <string name="migration_cling_use_default" msgid="2626475813981258626">"ТАЗАСЫН БАШТОО"</string> + <string name="workspace_cling_title" msgid="5626202359865825661">"Өз мейкиндигиңизди уюштуруңуз"</string> + <string name="workspace_cling_move_item" msgid="528201129978005352">"Тушкагаздарды, виджеттерди жана тууралоолорду башкаруу үчүн фонду басып туруңуз."</string> + <string name="folder_cling_title" msgid="3894908818693254164">"Мынакей фолдер"</string> + <string name="folder_cling_create_folder" msgid="6158215559475836131">"Башкасын түзүш үчүн колдонмону басып туруп, башканын жанына жылдырыңыз."</string> + <string name="cling_dismiss" msgid="8962359497601507581">"OK"</string> + <string name="folder_opened" msgid="94695026776264709">"Фолдер ачылды, туурасы <xliff:g id="WIDTH">%1$d</xliff:g>, бийиктиги <xliff:g id="HEIGHT">%2$d</xliff:g>"</string> + <string name="folder_tap_to_close" msgid="1884479294466410023">"Фолдерди жабыш үчүн тийиңиз"</string> + <string name="folder_tap_to_rename" msgid="9191075570492871147">"Тийип, аттын өзгөртүлүшүн сактаңыз"</string> + <string name="folder_closed" msgid="4100806530910930934">"Фолдер жабык"</string> + <string name="folder_renamed" msgid="1794088362165669656">"Фолдердин аты <xliff:g id="NAME">%1$s</xliff:g> деп өзгөртүлдү"</string> + <string name="folder_name_format" msgid="6629239338071103179">"Фолдер: <xliff:g id="NAME">%1$s</xliff:g>"</string> + <string name="widget_button_text" msgid="2880537293434387943">"Виджеттер"</string> + <string name="wallpaper_button_text" msgid="8404103075899945851">"Тушкагаздар"</string> + <string name="settings_button_text" msgid="8119458837558863227">"Тууралоолор"</string> + <string name="package_state_enqueued" msgid="6227252464303085641">"Күтүүдө"</string> + <string name="package_state_downloading" msgid="4088770468458724721">"Жүктөлп алнууда"</string> + <string name="package_state_installing" msgid="7588193972189849870">"Орнотулууда"</string> + <string name="package_state_unknown" msgid="7592128424511031410">"Белгисиз"</string> + <string name="package_state_error" msgid="7672093962724223588">"Калыбн келт. жок"</string> + <string name="abandoned_clean_all" msgid="5256770727689657618">"Баарын алып салуу"</string> + <string name="abandoned_clean_this" msgid="7610119707847920412">"Алып салуу"</string> + <string name="abandoned_search" msgid="891119232568284442">"Издөө"</string> + <string name="abandoned_promises_title" msgid="7096178467971716750">"Бул колдонмо орнотулган эмес"</string> + <string name="abandoned_promise_explanation" msgid="3990027586878167529">"Бул сүрөтчөнүн колдонмосу орнотулган эмес. Аны алып салсаңыз же колдонмону издеп, кол менен орнотсоңуз болот."</string> +</resources> diff --git a/res/values-land/dimens.xml b/res/values-land/dimens.xml index 07d92798d..1b3418154 100644 --- a/res/values-land/dimens.xml +++ b/res/values-land/dimens.xml @@ -23,6 +23,4 @@ <dimen name="apps_customize_tab_bar_height">42dp</dimen> <integer name="apps_customize_widget_cell_count_x">3</integer> <integer name="apps_customize_widget_cell_count_y">2</integer> - <integer name="apps_customize_cling_focused_x">2</integer> - <integer name="apps_customize_cling_focused_y">1</integer> </resources> diff --git a/res/values-lo-rLA/strings.xml b/res/values-lo-rLA/strings.xml index 50b5c08f4..1d953ffde 100644 --- a/res/values-lo-rLA/strings.xml +++ b/res/values-lo-rLA/strings.xml @@ -24,6 +24,7 @@ <string name="uid_name" msgid="7820867637514617527">"ແອັບພລິເຄຊັນຫຼັກຂອງ Android"</string> <string name="folder_name" msgid="7371454440695724752"></string> <string name="activity_not_found" msgid="8071924732094499514">"ແອັບຯບໍ່ໄດ້ຖືກຕິດຕັ້ງ."</string> + <string name="safemode_shortcut_error" msgid="9160126848219158407">"ແອັບຯທີ່ດາວໂຫລດແລ້ວຖືກປິດການນຳໃຊ້ໃນ Safe mode"</string> <string name="widgets_tab_label" msgid="2921133187116603919">"ວິດເຈັດ"</string> <string name="widget_adder" msgid="3201040140710381657">"ວິດເຈັດ"</string> <string name="toggle_weight_watcher" msgid="5645299835184636119">"ສະແດງຄວາມຈຳ"</string> @@ -76,6 +77,7 @@ <string name="permlab_write_settings" msgid="3574213698004620587">"ຂຽນການຕັ້ງຄ່າໜ້າຫຼັກ ແລະທາງລັດ"</string> <string name="permdesc_write_settings" msgid="5440712911516509985">"ອະນຸຍາດໃຫ້ແອັບຯດັ່ງກ່າວ ປ່ຽນການຕັ້ງຄ່າ ແລະທາງລັດໃນໜ້າຫຼັກ."</string> <string name="gadget_error_text" msgid="6081085226050792095">"ມີບັນຫາໃນການໂຫລດວິດເຈັດ"</string> + <string name="gadget_setup_text" msgid="8274003207686040488">"ຕິດຕັ້ງ"</string> <string name="uninstall_system_app_text" msgid="4172046090762920660">"ນີ້ແມ່ນແອັບຯຂອງລະບົບ ແລະບໍ່ສາມາດຖອນການຕິດຕັ້ງອອກໄດ້."</string> <string name="dream_name" msgid="1530253749244328964">"Rocket Launcher"</string> <string name="folder_hint_text" msgid="6617836969016293992">"ໂຟນເດີຍັງບໍ່ຖືກຕັ້ງຊື່"</string> @@ -95,6 +97,9 @@ <string name="migration_cling_use_default" msgid="2626475813981258626">"ເລີ່ມຕົ້ນໃໝ່"</string> <string name="workspace_cling_title" msgid="5626202359865825661">"ຈັດການພື້ນທີ່ຂອງທ່ານ"</string> <string name="workspace_cling_move_item" msgid="528201129978005352">"ແຕະຄ້າງໄວ້ທີ່ພາບພື້ນຫຼັງເພື່ອຈັດການພາບພື້ນຫຼັງ, ວິດເຈັດແລະການຕັ້ງຄ່າ."</string> + <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"ຮູບພື້ນຫຼັງ, ວິດເຈັດ, & ການຕັ້ງຄ່າ"</string> + <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"ແຕະທີ່ພາບພື້ນຫລັງຄ້າງໄວ້ເພື່ອປັບແຕ່ງ"</string> + <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"ເຂົ້າໃຈແລ້ວ"</string> <string name="folder_cling_title" msgid="3894908818693254164">"ນີ້ແມ່ນໂຟນເດີ"</string> <string name="folder_cling_create_folder" msgid="6158215559475836131">"ເພື່ອສ້າງອັນໃໝ່ແບບນີ້ ໃຫ້ແຕະຄ້າງໄວ້ທີ່ແອັບຯທີ່ຕ້ອງການຍ້າຍແລ້ວລາກມັນໄປຫາໂຕອື່ນ."</string> <string name="cling_dismiss" msgid="8962359497601507581">"ຕົກລົງ"</string> @@ -107,4 +112,14 @@ <string name="widget_button_text" msgid="2880537293434387943">"ວິດເຈັດ"</string> <string name="wallpaper_button_text" msgid="8404103075899945851">"ພາບພື້ນຫຼັງ"</string> <string name="settings_button_text" msgid="8119458837558863227">"ການຕັ້ງຄ່າ"</string> + <string name="package_state_enqueued" msgid="6227252464303085641">"ກຳລັງລໍຖ້າ"</string> + <string name="package_state_downloading" msgid="4088770468458724721">"ກຳລັງດາວໂຫລດ"</string> + <string name="package_state_installing" msgid="7588193972189849870">"ກຳລັງຕິດຕັ້ງ"</string> + <string name="package_state_unknown" msgid="7592128424511031410">"ບໍ່ຮູ້ຈັກ"</string> + <string name="package_state_error" msgid="7672093962724223588">"ບໍ່ໄດ້ກູ້ຂໍ້ມູນມາເທື່ອ"</string> + <string name="abandoned_clean_all" msgid="5256770727689657618">"ລຶບທັງໝົດ"</string> + <string name="abandoned_clean_this" msgid="7610119707847920412">"ລຶບ"</string> + <string name="abandoned_search" msgid="891119232568284442">"ຊອກຫາ"</string> + <string name="abandoned_promises_title" msgid="7096178467971716750">"ແອັບຯນີ້ຍັງບໍ່ໄດ້ຕິດຕັ້ງເທື່ອ"</string> + <string name="abandoned_promise_explanation" msgid="3990027586878167529">"ແອັບຯສຳລັບໄອຄອນນີ້ຍັງບໍ່ໄດ້ຕິດຕັ້ງເທື່ອ. ທ່ານສາມາດລຶບມັນອອກ ຫຼືຊອກຫາແອັບຯ ແລ້ວຕິດຕັ້ງມັນໄດ້ດ້ວຍຕົນເອງ."</string> </resources> diff --git a/res/values-lt/strings.xml b/res/values-lt/strings.xml index aba231d85..f7db79291 100644 --- a/res/values-lt/strings.xml +++ b/res/values-lt/strings.xml @@ -24,6 +24,7 @@ <string name="uid_name" msgid="7820867637514617527">"Pagrindinės „Android“ programos"</string> <string name="folder_name" msgid="7371454440695724752"></string> <string name="activity_not_found" msgid="8071924732094499514">"Programa neįdiegta."</string> + <string name="safemode_shortcut_error" msgid="9160126848219158407">"Atsisiųsta programa išjungta Saugos režimu"</string> <string name="widgets_tab_label" msgid="2921133187116603919">"Valdikliai"</string> <string name="widget_adder" msgid="3201040140710381657">"Valdikliai"</string> <string name="toggle_weight_watcher" msgid="5645299835184636119">"Rodyti atmintinę"</string> @@ -76,6 +77,7 @@ <string name="permlab_write_settings" msgid="3574213698004620587">"rašyti pagrindinio puslapio nustatymus ir sparčiuosius klavišus"</string> <string name="permdesc_write_settings" msgid="5440712911516509985">"Programai leidžiama keisti pagrindinio puslapio nustatymus ir sparčiuosius klavišus."</string> <string name="gadget_error_text" msgid="6081085226050792095">"Problema įkeliant valdiklį"</string> + <string name="gadget_setup_text" msgid="8274003207686040488">"Sąranka"</string> <string name="uninstall_system_app_text" msgid="4172046090762920660">"Tai sistemos programa ir jos negalima pašalinti."</string> <string name="dream_name" msgid="1530253749244328964">"Rocket Launcher"</string> <string name="folder_hint_text" msgid="6617836969016293992">"Aplankas be pavadinimo"</string> @@ -95,6 +97,9 @@ <string name="migration_cling_use_default" msgid="2626475813981258626">"PRADĖTI IŠ NAUJO"</string> <string name="workspace_cling_title" msgid="5626202359865825661">"Tvarkykite savo vietą"</string> <string name="workspace_cling_move_item" msgid="528201129978005352">"Palieskite ir laikykite foną, jei norite tvarkyti ekrano foną, valdiklius ir nustatymus."</string> + <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Ekrano fonai, valdikliai ir nustatymai"</string> + <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"Jei norite tinkinti, palieskite ir palaikykite foną"</string> + <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"SUPRATAU"</string> <string name="folder_cling_title" msgid="3894908818693254164">"Štai aplankas"</string> <string name="folder_cling_create_folder" msgid="6158215559475836131">"Kad sukurtumėte tokį patį, palieskite ir laikykite programą, tada perkelkite ją virš kitos programos."</string> <string name="cling_dismiss" msgid="8962359497601507581">"Gerai"</string> @@ -107,4 +112,14 @@ <string name="widget_button_text" msgid="2880537293434387943">"Valdikliai"</string> <string name="wallpaper_button_text" msgid="8404103075899945851">"Ekrano fonai"</string> <string name="settings_button_text" msgid="8119458837558863227">"Nustatymai"</string> + <string name="package_state_enqueued" msgid="6227252464303085641">"Laukiama"</string> + <string name="package_state_downloading" msgid="4088770468458724721">"Atsisiunčiama"</string> + <string name="package_state_installing" msgid="7588193972189849870">"Diegiama"</string> + <string name="package_state_unknown" msgid="7592128424511031410">"Nežinoma"</string> + <string name="package_state_error" msgid="7672093962724223588">"Neatkurta"</string> + <string name="abandoned_clean_all" msgid="5256770727689657618">"Pašalinti viską"</string> + <string name="abandoned_clean_this" msgid="7610119707847920412">"Pašalinti"</string> + <string name="abandoned_search" msgid="891119232568284442">"Ieškoti"</string> + <string name="abandoned_promises_title" msgid="7096178467971716750">"Ši programa neįdiegta"</string> + <string name="abandoned_promise_explanation" msgid="3990027586878167529">"Šios piktogramos programa neįdiegta. Galite ją pašalinti arba bandyti ieškoti programos ir ją įdiegti patys."</string> </resources> diff --git a/res/values-lv/strings.xml b/res/values-lv/strings.xml index 6d4888d8c..75eb0548b 100644 --- a/res/values-lv/strings.xml +++ b/res/values-lv/strings.xml @@ -24,6 +24,7 @@ <string name="uid_name" msgid="7820867637514617527">"Android pamatlietotnes"</string> <string name="folder_name" msgid="7371454440695724752"></string> <string name="activity_not_found" msgid="8071924732094499514">"Lietotne nav instalēta."</string> + <string name="safemode_shortcut_error" msgid="9160126848219158407">"Lejupielādētā lietotne ir atspējota drošajā režīmā."</string> <string name="widgets_tab_label" msgid="2921133187116603919">"Logrīki"</string> <string name="widget_adder" msgid="3201040140710381657">"Logrīki"</string> <string name="toggle_weight_watcher" msgid="5645299835184636119">"Rādīt atmiņu"</string> @@ -76,6 +77,7 @@ <string name="permlab_write_settings" msgid="3574213698004620587">"rakstīt sākuma ekrāna iestatījumus un saīsnes"</string> <string name="permdesc_write_settings" msgid="5440712911516509985">"Ļauj lietotnei mainīt iestatījumus un saīsnes sākuma ekrānā."</string> <string name="gadget_error_text" msgid="6081085226050792095">"Ielādējot logrīku, radās problēma."</string> + <string name="gadget_setup_text" msgid="8274003207686040488">"Notiek iestatīšana"</string> <string name="uninstall_system_app_text" msgid="4172046090762920660">"Šī ir sistēmas lietotne, un to nevar atinstalēt."</string> <string name="dream_name" msgid="1530253749244328964">"Rocket Launcher"</string> <string name="folder_hint_text" msgid="6617836969016293992">"Mape bez nosaukuma"</string> @@ -95,6 +97,9 @@ <string name="migration_cling_use_default" msgid="2626475813981258626">"SĀKT NO SĀKUMA"</string> <string name="workspace_cling_title" msgid="5626202359865825661">"Kārtojiet savu darbvietu"</string> <string name="workspace_cling_move_item" msgid="528201129978005352">"Pieskarieties fonam un turiet to, lai pārvaldītu fona tapeti, logrīkus un iestatījumus."</string> + <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Fona tapetes, logrīki un iestatījumi"</string> + <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"Lai pielāgotu, pieskarieties fonam un turiet to nospiestu."</string> + <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"SAPRATU!"</string> <string name="folder_cling_title" msgid="3894908818693254164">"Lūk, mape!"</string> <string name="folder_cling_create_folder" msgid="6158215559475836131">"Lai izveidotu tādu pašu, pieskarieties lietotnei un turiet to, pēc tam pārvietojiet to virs citas lietotnes."</string> <string name="cling_dismiss" msgid="8962359497601507581">"Labi"</string> @@ -107,4 +112,14 @@ <string name="widget_button_text" msgid="2880537293434387943">"Logrīki"</string> <string name="wallpaper_button_text" msgid="8404103075899945851">"Fona tapetes"</string> <string name="settings_button_text" msgid="8119458837558863227">"Iestatījumi"</string> + <string name="package_state_enqueued" msgid="6227252464303085641">"Gaida"</string> + <string name="package_state_downloading" msgid="4088770468458724721">"Lejupielādē"</string> + <string name="package_state_installing" msgid="7588193972189849870">"Instalē"</string> + <string name="package_state_unknown" msgid="7592128424511031410">"Nezināma"</string> + <string name="package_state_error" msgid="7672093962724223588">"Nav atjaunota"</string> + <string name="abandoned_clean_all" msgid="5256770727689657618">"Noņemt visas"</string> + <string name="abandoned_clean_this" msgid="7610119707847920412">"Noņemt"</string> + <string name="abandoned_search" msgid="891119232568284442">"Meklēt"</string> + <string name="abandoned_promises_title" msgid="7096178467971716750">"Šī lietotne nav instalēta"</string> + <string name="abandoned_promise_explanation" msgid="3990027586878167529">"Šai ikonai paredzētā lietotne nav instalēta. Varat noņemt ikonu vai meklēt lietotni un instalēt to manuāli."</string> </resources> diff --git a/res/values-mk-rMK/strings.xml b/res/values-mk-rMK/strings.xml new file mode 100644 index 000000000..0d775712f --- /dev/null +++ b/res/values-mk-rMK/strings.xml @@ -0,0 +1,121 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +* Copyright (C) 2008 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. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="application_name" msgid="5181331383435256801">"Launcher3"</string> + <string name="home" msgid="7658288663002113681">"Почетна страница"</string> + <string name="uid_name" msgid="7820867637514617527">"Основни апликации на Android"</string> + <string name="folder_name" msgid="7371454440695724752"></string> + <string name="activity_not_found" msgid="8071924732094499514">"Апликацијата не е инсталирана."</string> + <string name="safemode_shortcut_error" msgid="9160126848219158407">"Преземената апликација е оневозможена во безбеден режим"</string> + <string name="widgets_tab_label" msgid="2921133187116603919">"Виџети"</string> + <string name="widget_adder" msgid="3201040140710381657">"Виџети"</string> + <string name="toggle_weight_watcher" msgid="5645299835184636119">"Прикажи „Мени“"</string> + <string name="long_press_widget_to_add" msgid="7699152356777458215">"Допри и задржи за да се избере виџетот."</string> + <string name="market" msgid="2619650989819296998">"Продавница"</string> + <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string> + <string name="external_drop_widget_error" msgid="3165821058322217155">"Не можеше да се спушти елемент на овој екран на почетната страница."</string> + <string name="external_drop_widget_pick_title" msgid="3486317258037690630">"Избери виџет за да се создаде"</string> + <string name="rename_folder_label" msgid="3727762225964550653">"Име на папка"</string> + <string name="rename_folder_title" msgid="3771389277707820891">"Преименувај папка"</string> + <string name="rename_action" msgid="5559600076028658757">"Во ред"</string> + <string name="cancel_action" msgid="7009134900002915310">"Откажи"</string> + <string name="menu_item_add_item" msgid="1264911265836810421">"Додај во екран на почетна страница"</string> + <string name="group_applications" msgid="3797214114206693605">"Апликации"</string> + <string name="group_shortcuts" msgid="6012256992764410535">"Кратенки"</string> + <string name="group_widgets" msgid="1569030723286851002">"Виџети"</string> + <string name="completely_out_of_space" msgid="6106288382070760318">"Нема повеќе простор на вашите екрани на почетна страница."</string> + <string name="out_of_space" msgid="4691004494942118364">"Нема повеќе простор на овој екран на почетната страница."</string> + <string name="hotseat_out_of_space" msgid="7448809638125333693">"Нема повеќе простор на лентата „Омилени“"</string> + <string name="invalid_hotseat_item" msgid="5779907847267573691">"Овој виџет е премногу голем за лентата „Омилени“"</string> + <string name="shortcut_installed" msgid="1701742129426969556">"Кратенката „<xliff:g id="NAME">%s</xliff:g>“ е создадена."</string> + <string name="shortcut_uninstalled" msgid="8176767991305701821">"Кратенката „<xliff:g id="NAME">%s</xliff:g>“ е отстранета."</string> + <string name="shortcut_duplicate" msgid="9167217446062498127">"Кратенката „<xliff:g id="NAME">%s</xliff:g>“ веќе постои."</string> + <string name="title_select_shortcut" msgid="6680642571148153868">"Избери кратенка"</string> + <string name="title_select_application" msgid="3280812711670683644">"Избери апликација"</string> + <string name="all_apps_button_label" msgid="9110807029020582876">"Апликации"</string> + <string name="all_apps_home_button_label" msgid="252062713717058851">"Почетна страница"</string> + <string name="delete_zone_label_workspace" msgid="4009607676751398685">"Отстрани"</string> + <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"Деинсталирај"</string> + <string name="delete_target_label" msgid="1822697352535677073">"Отстрани"</string> + <string name="delete_target_uninstall_label" msgid="5100785476250872595">"Деинсталирај"</string> + <string name="info_target_label" msgid="8053346143994679532">"Информации за апликацијата"</string> + <string name="accessibility_search_button" msgid="1628520399424565142">"Пребарај"</string> + <string name="accessibility_voice_search_button" msgid="4637324840434406584">"Гласовно пребарување"</string> + <string name="accessibility_all_apps_button" msgid="2603132375383800483">"Апликации"</string> + <string name="accessibility_delete_button" msgid="6466114477993744621">"Отстрани"</string> + <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"Деинсталирај ажурирање"</string> + <string name="cab_menu_delete_app" msgid="7435191475867183689">"Деинсталирај апликација"</string> + <string name="cab_menu_app_info" msgid="8593722221450362342">"Детали за апликација"</string> + <string name="cab_app_selection_text" msgid="374688303047985416">"1 апликација е избрана"</string> + <string name="cab_widget_selection_text" msgid="1833458597831541241">"1 виџет е избран"</string> + <string name="cab_folder_selection_text" msgid="7999992513806132118">"1 папка е избрана"</string> + <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"1 кратенка е избрана"</string> + <string name="permlab_install_shortcut" msgid="5632423390354674437">"инсталирај кратенки"</string> + <string name="permdesc_install_shortcut" msgid="923466509822011139">"Овозможува апликацијата да додава кратенки без интервенција на корисникот."</string> + <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"деинсталирај кратенки"</string> + <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"Овозможува апликацијата да ги отстрани кратенките без интервенција на корисникот."</string> + <string name="permlab_read_settings" msgid="1941457408239617576">"прочитај подесувања и кратенки на почетна страница"</string> + <string name="permdesc_read_settings" msgid="5833423719057558387">"Овозможува апликацијата да ги менува подесувањата и кратенките на почетната страница."</string> + <string name="permlab_write_settings" msgid="3574213698004620587">"напиши подесувања и кратенки на почетна страница"</string> + <string name="permdesc_write_settings" msgid="5440712911516509985">"Овозможува апликацијата да ги менува подесувањата и кратенките на почетната страница."</string> + <string name="gadget_error_text" msgid="6081085226050792095">"Проблем при вчитувањето на виџетот"</string> + <string name="uninstall_system_app_text" msgid="4172046090762920660">"Ова е системска апликација и не може да се деинсталира."</string> + <string name="dream_name" msgid="1530253749244328964">"Rocket Launcher"</string> + <string name="folder_hint_text" msgid="6617836969016293992">"Неименувана папка"</string> + <string name="workspace_description_format" msgid="2950174241104043327">"Екран на почетна страница %1$d"</string> + <string name="default_scroll_format" msgid="7475544710230993317">"Страница %1$d од %2$d"</string> + <string name="workspace_scroll_format" msgid="8458889198184077399">"Екран на почетна страница %1$d од %2$d"</string> + <string name="apps_customize_apps_scroll_format" msgid="370005296147130238">"Страница на апликации %1$d од %2$d"</string> + <string name="apps_customize_widgets_scroll_format" msgid="3106209519974971521">"Страница на виџети %1$d од %2$d"</string> + <string name="first_run_cling_title" msgid="2459738000155917941">"Добредојдовте"</string> + <string name="first_run_cling_description" msgid="6447072552696253358">"Чувствувајте се како дома."</string> + <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string> + <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string> + <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"Создади повеќе екрани за апликации и папки"</string> + <string name="migration_cling_title" msgid="9181776667882933767">"Копирај икони за апликација"</string> + <string name="migration_cling_description" msgid="2752413805582227644">"Увези икони и папки од старите екрани на почетната страница?"</string> + <string name="migration_cling_copy_apps" msgid="946331230090919440">"КОПИРАЈ ИКОНИ"</string> + <string name="migration_cling_use_default" msgid="2626475813981258626">"СТАРТУВАЈ ОД ПОЧЕТОК"</string> + <string name="workspace_cling_title" msgid="5626202359865825661">"Организирајте го вашиот простор"</string> + <string name="workspace_cling_move_item" msgid="528201129978005352">"Допри и задржи ја заднината за управување со тапети, виџети и подесувања."</string> + <string name="folder_cling_title" msgid="3894908818693254164">"Еве папка"</string> + <string name="folder_cling_create_folder" msgid="6158215559475836131">"За да создадете ваква, допрете и држете ја апликацијата, а потоа поместете ја врз другата."</string> + <string name="cling_dismiss" msgid="8962359497601507581">"Во ред"</string> + <string name="folder_opened" msgid="94695026776264709">"Отворена е папка, <xliff:g id="WIDTH">%1$d</xliff:g> на <xliff:g id="HEIGHT">%2$d</xliff:g>"</string> + <string name="folder_tap_to_close" msgid="1884479294466410023">"Допри за да се затвори папката"</string> + <string name="folder_tap_to_rename" msgid="9191075570492871147">"Допри за да се зачува преименувањето"</string> + <string name="folder_closed" msgid="4100806530910930934">"Папката е затворена"</string> + <string name="folder_renamed" msgid="1794088362165669656">"Папката е преименувана во <xliff:g id="NAME">%1$s</xliff:g>"</string> + <string name="folder_name_format" msgid="6629239338071103179">"Папка: <xliff:g id="NAME">%1$s</xliff:g>"</string> + <string name="widget_button_text" msgid="2880537293434387943">"Виџети"</string> + <string name="wallpaper_button_text" msgid="8404103075899945851">"Тапети"</string> + <string name="settings_button_text" msgid="8119458837558863227">"Подесувања"</string> + <string name="package_state_enqueued" msgid="6227252464303085641">"На чекање"</string> + <string name="package_state_downloading" msgid="4088770468458724721">"Се презема"</string> + <string name="package_state_installing" msgid="7588193972189849870">"Се инсталира"</string> + <string name="package_state_unknown" msgid="7592128424511031410">"Непознато"</string> + <string name="package_state_error" msgid="7672093962724223588">"Не е обновено"</string> + <string name="abandoned_clean_all" msgid="5256770727689657618">"Отстрани ги сите"</string> + <string name="abandoned_clean_this" msgid="7610119707847920412">"Отстрани"</string> + <string name="abandoned_search" msgid="891119232568284442">"Барај"</string> + <string name="abandoned_promises_title" msgid="7096178467971716750">"Апликацијата не е инсталирана"</string> + <string name="abandoned_promise_explanation" msgid="3990027586878167529">"Апликацијата за оваа икона не е инсталирана. Може да ја отстраните или да се обидете да ја најдете апликацијата и да ја инсталирате рачно."</string> +</resources> diff --git a/res/values-ml-rIN/strings.xml b/res/values-ml-rIN/strings.xml new file mode 100644 index 000000000..32329f1c5 --- /dev/null +++ b/res/values-ml-rIN/strings.xml @@ -0,0 +1,121 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +* Copyright (C) 2008 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. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="application_name" msgid="5181331383435256801">"Launcher3"</string> + <string name="home" msgid="7658288663002113681">"ഹോം"</string> + <string name="uid_name" msgid="7820867637514617527">"Android Core അപ്ലിക്കേഷനുകൾ"</string> + <string name="folder_name" msgid="7371454440695724752"></string> + <string name="activity_not_found" msgid="8071924732094499514">"അപ്ലിക്കേഷൻ ഇൻസ്റ്റാളുചെയ്തിട്ടില്ല."</string> + <string name="safemode_shortcut_error" msgid="9160126848219158407">"ഡൗൺലോഡുചെയ്ത അപ്ലിക്കേഷൻ സുരക്ഷാ മോഡിൽ പ്രവർത്തനരഹിതമാക്കി"</string> + <string name="widgets_tab_label" msgid="2921133187116603919">"വിജറ്റുകൾ"</string> + <string name="widget_adder" msgid="3201040140710381657">"വിജറ്റുകൾ"</string> + <string name="toggle_weight_watcher" msgid="5645299835184636119">"മെമ്മറി കാണിക്കുക"</string> + <string name="long_press_widget_to_add" msgid="7699152356777458215">"ഒരു വിജറ്റ് ചേർക്കുന്നതിന് അത് സ്പർശിച്ച് പിടിക്കുക."</string> + <string name="market" msgid="2619650989819296998">"ഷോപ്പുചെയ്യുക"</string> + <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string> + <string name="external_drop_widget_error" msgid="3165821058322217155">"ഹോം സ്ക്രീനിൽ ഇനം വലിച്ചിടാനായില്ല."</string> + <string name="external_drop_widget_pick_title" msgid="3486317258037690630">"സൃഷ്ടിക്കുന്നതിന് വിജറ്റ് തിരഞ്ഞെടുക്കുക"</string> + <string name="rename_folder_label" msgid="3727762225964550653">"ഫോൾഡറിന്റെ പേര്"</string> + <string name="rename_folder_title" msgid="3771389277707820891">"ഫോൾഡറിന്റെ പേരുമാറ്റുക"</string> + <string name="rename_action" msgid="5559600076028658757">"ശരി"</string> + <string name="cancel_action" msgid="7009134900002915310">"റദ്ദാക്കുക"</string> + <string name="menu_item_add_item" msgid="1264911265836810421">"ഹോം സ്ക്രീനിൽ ചേർക്കുക"</string> + <string name="group_applications" msgid="3797214114206693605">"അപ്ലിക്കേഷനുകൾ"</string> + <string name="group_shortcuts" msgid="6012256992764410535">"കുറുക്കുവഴികൾ"</string> + <string name="group_widgets" msgid="1569030723286851002">"വിജറ്റുകൾ"</string> + <string name="completely_out_of_space" msgid="6106288382070760318">"നിങ്ങളുടെ ഹോം സ്ക്രീനുകളിൽ സ്ഥലമില്ല."</string> + <string name="out_of_space" msgid="4691004494942118364">"ഈ ഹോം സ്ക്രീനിൽ ഒഴിവൊന്നുമില്ല."</string> + <string name="hotseat_out_of_space" msgid="7448809638125333693">"പ്രിയപ്പെട്ടവയുടെ ട്രേയിൽ ഒഴിവൊന്നുമില്ല"</string> + <string name="invalid_hotseat_item" msgid="5779907847267573691">"ഈ വിജറ്റ് പ്രിയപ്പെട്ടവയുടെ ട്രേയിൽ ഉൾക്കൊള്ളിക്കാവുന്നതിലും വളരെ വലുതാണ്"</string> + <string name="shortcut_installed" msgid="1701742129426969556">"കുറുക്കുവഴി \"<xliff:g id="NAME">%s</xliff:g>\" സൃഷ്ടിച്ചു."</string> + <string name="shortcut_uninstalled" msgid="8176767991305701821">"കുറുക്കുവഴി \"<xliff:g id="NAME">%s</xliff:g>\" നീക്കംചെയ്തു."</string> + <string name="shortcut_duplicate" msgid="9167217446062498127">"കുറുക്കുവഴി \"<xliff:g id="NAME">%s</xliff:g>\" ഇതിനകം നിലവിലുണ്ട്."</string> + <string name="title_select_shortcut" msgid="6680642571148153868">"കുറുക്കുവഴി തിരഞ്ഞെടുക്കുക"</string> + <string name="title_select_application" msgid="3280812711670683644">"അപ്ലിക്കേഷൻ തിരഞ്ഞെടുക്കുക"</string> + <string name="all_apps_button_label" msgid="9110807029020582876">"അപ്ലിക്കേഷനുകൾ"</string> + <string name="all_apps_home_button_label" msgid="252062713717058851">"ഹോം"</string> + <string name="delete_zone_label_workspace" msgid="4009607676751398685">"നീക്കംചെയ്യുക"</string> + <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"അണ്ഇസ്റ്റാളുചെയ്യുക"</string> + <string name="delete_target_label" msgid="1822697352535677073">"നീക്കംചെയ്യുക"</string> + <string name="delete_target_uninstall_label" msgid="5100785476250872595">"അണ്ഇസ്റ്റാളുചെയ്യുക"</string> + <string name="info_target_label" msgid="8053346143994679532">"അപ്ലിക്കേഷൻ വിവരം"</string> + <string name="accessibility_search_button" msgid="1628520399424565142">"തിരയുക"</string> + <string name="accessibility_voice_search_button" msgid="4637324840434406584">"വോയ്സ് തിരയൽ"</string> + <string name="accessibility_all_apps_button" msgid="2603132375383800483">"അപ്ലിക്കേഷനുകൾ"</string> + <string name="accessibility_delete_button" msgid="6466114477993744621">"നീക്കംചെയ്യുക"</string> + <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"അപ്ഡേറ്റ് അൺഇൻസ്റ്റാളുചെയ്യുക"</string> + <string name="cab_menu_delete_app" msgid="7435191475867183689">"അപ്ലിക്കേഷൻ അൺഇൻസ്റ്റാളുചെയ്യുക"</string> + <string name="cab_menu_app_info" msgid="8593722221450362342">"അപ്ലിക്കേഷൻ വിശദാംശങ്ങൾ"</string> + <string name="cab_app_selection_text" msgid="374688303047985416">"ഒരു അപ്ലിക്കേഷൻ തിരഞ്ഞെടുത്തു"</string> + <string name="cab_widget_selection_text" msgid="1833458597831541241">"ഒരു വിജറ്റ് തിരഞ്ഞെടുത്തു"</string> + <string name="cab_folder_selection_text" msgid="7999992513806132118">"ഒരു ഫോൾഡർ തിരഞ്ഞെടുത്തു"</string> + <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"ഒരു കുറുക്കുവഴി തിരഞ്ഞെടുത്തു"</string> + <string name="permlab_install_shortcut" msgid="5632423390354674437">"കുറുക്കുവഴികൾ ഇൻസ്റ്റാളുചെയ്യുക"</string> + <string name="permdesc_install_shortcut" msgid="923466509822011139">"ഉപയോക്തൃ ഇടപെടൽ ഇല്ലാതെ കുറുക്കുവഴികൾ ചേർക്കാൻ അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു."</string> + <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"കുറുക്കുവഴികൾ അൺഇൻസ്റ്റാളുചെയ്യുക"</string> + <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"ഉപയോക്തൃ ഇടപെടൽ ഇല്ലാതെ കുറുക്കുവഴികൾ നീക്കംചെയ്യാൻ അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു."</string> + <string name="permlab_read_settings" msgid="1941457408239617576">"ഹോം ക്രമീകരണങ്ങളും കുറുക്കുവഴികളും റീഡുചെയ്യുക"</string> + <string name="permdesc_read_settings" msgid="5833423719057558387">"ഹോമിലെ ക്രമീകരണങ്ങളും കുറുക്കുവഴികളും റീഡുചെയ്യാൻ അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു."</string> + <string name="permlab_write_settings" msgid="3574213698004620587">"ഹോം ക്രമീകരണങ്ങളും കുറുക്കുവഴികളും റൈറ്റുചെയ്യുക"</string> + <string name="permdesc_write_settings" msgid="5440712911516509985">"ഹോമിലെ ക്രമീകരണങ്ങളും കുറുക്കുവഴികളും മാറ്റാൻ അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു."</string> + <string name="gadget_error_text" msgid="6081085226050792095">"വിജറ്റ് ലോഡുചെയ്യുന്നതിൽ പ്രശ്നമുണ്ട്"</string> + <string name="uninstall_system_app_text" msgid="4172046090762920660">"ഇതൊരു സിസ്റ്റം അപ്ലിക്കേഷനായതിനാൽ അൺഇൻസ്റ്റാളുചെയ്യാനാവില്ല."</string> + <string name="dream_name" msgid="1530253749244328964">"റോക്കറ്റ് ലോഞ്ചർ"</string> + <string name="folder_hint_text" msgid="6617836969016293992">"പേരുനൽകാത്ത ഫോൾഡർ"</string> + <string name="workspace_description_format" msgid="2950174241104043327">"ഹോം സ്ക്രീൻ %1$d"</string> + <string name="default_scroll_format" msgid="7475544710230993317">"പേജ് %1$d / %2$d"</string> + <string name="workspace_scroll_format" msgid="8458889198184077399">"ഹോം സ്ക്രീൻ %1$d / %2$d"</string> + <string name="apps_customize_apps_scroll_format" msgid="370005296147130238">"അപ്ലിക്കേഷനുകളുടെ പേജ് %1$d / %2$d"</string> + <string name="apps_customize_widgets_scroll_format" msgid="3106209519974971521">"വിജറ്റുകളുടെ പേജ് %1$d / %2$d"</string> + <string name="first_run_cling_title" msgid="2459738000155917941">"സ്വാഗതം"</string> + <string name="first_run_cling_description" msgid="6447072552696253358">"ഹോം നിങ്ങളുടേതാക്കി മാറ്റുക."</string> + <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string> + <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string> + <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"അപ്ലിക്കേഷനുകൾക്കും ഫോൾഡറുകൾക്കും വേണ്ടി കൂടുതൽ സ്ക്രീനുകൾ സൃഷ്ടിക്കുക"</string> + <string name="migration_cling_title" msgid="9181776667882933767">"നിങ്ങളുടെ അപ്ലിക്കേഷൻ ഐക്കണുകൾ പകർത്തുക"</string> + <string name="migration_cling_description" msgid="2752413805582227644">"നിങ്ങളുടെ പഴയ ഹോം സ്ക്രീനുകളിൽ നിന്ന് ഐക്കണുകളും ഫോൾഡറുകളും ഇമ്പോർട്ടുചെയ്യണോ?"</string> + <string name="migration_cling_copy_apps" msgid="946331230090919440">"ഐക്കണുകൾ പകർത്തുക"</string> + <string name="migration_cling_use_default" msgid="2626475813981258626">"പുതുതായി ആരംഭിക്കുക"</string> + <string name="workspace_cling_title" msgid="5626202359865825661">"നിങ്ങളുടെ ഇടം ഓർഗനൈസുചെയ്യുക"</string> + <string name="workspace_cling_move_item" msgid="528201129978005352">"വാൾപേപ്പർ, വിജറ്റുകൾ, ക്രമീകരണങ്ങൾ എന്നിവ നിയന്ത്രിക്കുന്നതിന് പശ്ചാത്തലം സ്പർശിച്ച് പിടിക്കുക."</string> + <string name="folder_cling_title" msgid="3894908818693254164">"ഇവിടെയൊരു ഫോൾഡർ ഉണ്ട്"</string> + <string name="folder_cling_create_folder" msgid="6158215559475836131">"ഇതുപോലൊന്ന് സൃഷ്ടിക്കുന്നതിന്, ഒരു അപ്ലിക്കേഷൻ സ്പർശിച്ച് പിടിച്ചുകൊണ്ട് അത് മറ്റൊന്നിലേക്ക് നീക്കുക."</string> + <string name="cling_dismiss" msgid="8962359497601507581">"ശരി"</string> + <string name="folder_opened" msgid="94695026776264709">"ഫോൾഡർ തുറന്നു, <xliff:g id="WIDTH">%1$d</xliff:g> / <xliff:g id="HEIGHT">%2$d</xliff:g>"</string> + <string name="folder_tap_to_close" msgid="1884479294466410023">"ഫോൾഡർ അടയ്ക്കാൻ സ്പർശിക്കുക"</string> + <string name="folder_tap_to_rename" msgid="9191075570492871147">"പേരുമാറ്റം സംരക്ഷിക്കുന്നതിന് സ്പർശിക്കുക"</string> + <string name="folder_closed" msgid="4100806530910930934">"ഫോൾഡർ അടച്ചു"</string> + <string name="folder_renamed" msgid="1794088362165669656">"ഫോൾഡറിന്റെ പേര് <xliff:g id="NAME">%1$s</xliff:g> എന്നായി മാറ്റി"</string> + <string name="folder_name_format" msgid="6629239338071103179">"ഫോൾഡർ: <xliff:g id="NAME">%1$s</xliff:g>"</string> + <string name="widget_button_text" msgid="2880537293434387943">"വിജറ്റുകൾ"</string> + <string name="wallpaper_button_text" msgid="8404103075899945851">"വാൾപേപ്പറുകൾ"</string> + <string name="settings_button_text" msgid="8119458837558863227">"ക്രമീകരണങ്ങൾ"</string> + <string name="package_state_enqueued" msgid="6227252464303085641">"കാത്തിരിക്കുന്നു"</string> + <string name="package_state_downloading" msgid="4088770468458724721">"ഡൗൺലോഡുചെയ്യുന്നു"</string> + <string name="package_state_installing" msgid="7588193972189849870">"ഇൻസ്റ്റാൾ ചെയ്യുന്നു"</string> + <string name="package_state_unknown" msgid="7592128424511031410">"അജ്ഞാതം"</string> + <string name="package_state_error" msgid="7672093962724223588">"പുനഃസ്ഥാപിച്ചിട്ടില്ല"</string> + <string name="abandoned_clean_all" msgid="5256770727689657618">"എല്ലാം നീക്കം ചെയ്യുക"</string> + <string name="abandoned_clean_this" msgid="7610119707847920412">"നീക്കംചെയ്യുക"</string> + <string name="abandoned_search" msgid="891119232568284442">"തിരയുക"</string> + <string name="abandoned_promises_title" msgid="7096178467971716750">"ഈ അപ്ലിക്കേഷൻ ഇൻസ്റ്റാളുചെയ്തിട്ടില്ല"</string> + <string name="abandoned_promise_explanation" msgid="3990027586878167529">"ഈ ഐക്കണുവേണ്ടി അപ്ലിക്കേഷൻ ഇൻസ്റ്റാളുചെയ്തിട്ടില്ല. നിങ്ങൾക്കത് നീക്കംചെയ്യാനാകും അല്ലെങ്കിൽ അപ്ലിക്കേഷനുവേണ്ടി തിരഞ്ഞുകൊണ്ട് അത് സ്വമേധയാ ഇൻസ്റ്റാളുചെയ്യുക."</string> +</resources> diff --git a/res/values-mn-rMN/strings.xml b/res/values-mn-rMN/strings.xml index db92a5c81..34fb79423 100644 --- a/res/values-mn-rMN/strings.xml +++ b/res/values-mn-rMN/strings.xml @@ -24,6 +24,7 @@ <string name="uid_name" msgid="7820867637514617527">"Андройд үндсэн апп"</string> <string name="folder_name" msgid="7371454440695724752"></string> <string name="activity_not_found" msgid="8071924732094499514">"Апп суугаагүй байна."</string> + <string name="safemode_shortcut_error" msgid="9160126848219158407">"Татаж авсан апп-г Аюулгүй горим дотроос идэвхгүйжүүлсэн"</string> <string name="widgets_tab_label" msgid="2921133187116603919">"Виджет"</string> <string name="widget_adder" msgid="3201040140710381657">"Виджет"</string> <string name="toggle_weight_watcher" msgid="5645299835184636119">"Мем харуулах"</string> @@ -76,6 +77,7 @@ <string name="permlab_write_settings" msgid="3574213698004620587">"Нүүрний тохиргоо болон товчлолыг бичих"</string> <string name="permdesc_write_settings" msgid="5440712911516509985">"Апп нь Нүүрэндэх товчлол болон тохиргоог өөрчилж чадна."</string> <string name="gadget_error_text" msgid="6081085226050792095">"Виджет ачаалахад асуудал гарав"</string> + <string name="gadget_setup_text" msgid="8274003207686040488">"Тохируулга"</string> <string name="uninstall_system_app_text" msgid="4172046090762920660">"Энэ апп нь системийн апп ба устгах боломжгүй."</string> <string name="dream_name" msgid="1530253749244328964">"Пуужин хөөргөгч"</string> <string name="folder_hint_text" msgid="6617836969016293992">"Нэргүй фолдер"</string> @@ -95,6 +97,9 @@ <string name="migration_cling_use_default" msgid="2626475813981258626">"ШИНЭЭР ЭХЛЭХ"</string> <string name="workspace_cling_title" msgid="5626202359865825661">"Өөрийнхөө зайг тохируулаарай"</string> <string name="workspace_cling_move_item" msgid="528201129978005352">"Арын дэвсгэр дээр хүрээд & дарснаар ханын зураг, виджет болон тохиргоог өөрчилж болно."</string> + <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Дэвсгэр зураг, виджет, & тохиргоо"</string> + <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"Тааруулахын тулд арын дэлгэцэнд хүрээд & барина уу"</string> + <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"Ойлголоо"</string> <string name="folder_cling_title" msgid="3894908818693254164">"Фолдер энд байна"</string> <string name="folder_cling_create_folder" msgid="6158215559475836131">"Үүнтэй адилханыг үүсгэхийн тулд апп дээр хүрч & бариад нөгөөхийн дээр зөөнө үү."</string> <string name="cling_dismiss" msgid="8962359497601507581">"Тийм"</string> @@ -107,4 +112,14 @@ <string name="widget_button_text" msgid="2880537293434387943">"Виджет"</string> <string name="wallpaper_button_text" msgid="8404103075899945851">"Ханын зураг"</string> <string name="settings_button_text" msgid="8119458837558863227">"Тохиргоо"</string> + <string name="package_state_enqueued" msgid="6227252464303085641">"Хүлээж байна"</string> + <string name="package_state_downloading" msgid="4088770468458724721">"Татаж авч байна"</string> + <string name="package_state_installing" msgid="7588193972189849870">"Суулгаж байна"</string> + <string name="package_state_unknown" msgid="7592128424511031410">"Тодорхойгүй"</string> + <string name="package_state_error" msgid="7672093962724223588">"Сэргээгээгүй"</string> + <string name="abandoned_clean_all" msgid="5256770727689657618">"Бүгдийг устгах"</string> + <string name="abandoned_clean_this" msgid="7610119707847920412">"Устгах"</string> + <string name="abandoned_search" msgid="891119232568284442">"Хайх"</string> + <string name="abandoned_promises_title" msgid="7096178467971716750">"Энэ апп-г суулгаагүй байна"</string> + <string name="abandoned_promise_explanation" msgid="3990027586878167529">"Энэ дүрсний апп-г суулгаагүй байна. Та үүнийг устгах буюу апп-г хайж суулгах боломжтой."</string> </resources> diff --git a/res/values-mr-rIN/strings.xml b/res/values-mr-rIN/strings.xml new file mode 100644 index 000000000..2e51e7b26 --- /dev/null +++ b/res/values-mr-rIN/strings.xml @@ -0,0 +1,121 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +* Copyright (C) 2008 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. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="application_name" msgid="5181331383435256801">"Launcher3"</string> + <string name="home" msgid="7658288663002113681">"मुख्यपृष्ठ"</string> + <string name="uid_name" msgid="7820867637514617527">"Android Core Apps"</string> + <string name="folder_name" msgid="7371454440695724752"></string> + <string name="activity_not_found" msgid="8071924732094499514">"अॅप स्थापित केलेला नाही."</string> + <string name="safemode_shortcut_error" msgid="9160126848219158407">"डाउनलोड केलेला अॅप सुरक्षित मोड मध्ये अक्षम केला"</string> + <string name="widgets_tab_label" msgid="2921133187116603919">"विजेट"</string> + <string name="widget_adder" msgid="3201040140710381657">"विजेट"</string> + <string name="toggle_weight_watcher" msgid="5645299835184636119">"Mem दर्शवा"</string> + <string name="long_press_widget_to_add" msgid="7699152356777458215">"विजेट निवडण्यासाठी स्पर्श करा आणि धरून ठेवा."</string> + <string name="market" msgid="2619650989819296998">"खरेदी करा"</string> + <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string> + <string name="external_drop_widget_error" msgid="3165821058322217155">"या मुख्य स्क्रीनवर आयटम ड्रॉप करू शकलो नाही."</string> + <string name="external_drop_widget_pick_title" msgid="3486317258037690630">"तयार करण्यासाठी विजेट निवडा"</string> + <string name="rename_folder_label" msgid="3727762225964550653">"फोल्डर नाव"</string> + <string name="rename_folder_title" msgid="3771389277707820891">"फोल्डरचे नाव बदला"</string> + <string name="rename_action" msgid="5559600076028658757">"ठीक"</string> + <string name="cancel_action" msgid="7009134900002915310">"रद्द करा"</string> + <string name="menu_item_add_item" msgid="1264911265836810421">"मुख्य स्क्रीनवर जोडा"</string> + <string name="group_applications" msgid="3797214114206693605">"अॅप्स"</string> + <string name="group_shortcuts" msgid="6012256992764410535">"शॉर्टकट"</string> + <string name="group_widgets" msgid="1569030723286851002">"विजेट"</string> + <string name="completely_out_of_space" msgid="6106288382070760318">"आपल्या मुख्य स्क्रीनवर अधिक जागा नाही."</string> + <string name="out_of_space" msgid="4691004494942118364">"या मुख्य स्क्रीनवर आणखी जागा नाही."</string> + <string name="hotseat_out_of_space" msgid="7448809638125333693">"आवडीच्या ट्रे मध्ये आणखी जागा नाही"</string> + <string name="invalid_hotseat_item" msgid="5779907847267573691">"हे विजेट आवडत्या ट्रे साठी खूप मोठे आहे"</string> + <string name="shortcut_installed" msgid="1701742129426969556">"\"<xliff:g id="NAME">%s</xliff:g>\" शॉर्टकट तयार केला."</string> + <string name="shortcut_uninstalled" msgid="8176767991305701821">"\"<xliff:g id="NAME">%s</xliff:g>\" शॉर्टकट काढला."</string> + <string name="shortcut_duplicate" msgid="9167217446062498127">"\"<xliff:g id="NAME">%s</xliff:g>\" शॉर्टकट आधीपासून अस्तित्वात आहे."</string> + <string name="title_select_shortcut" msgid="6680642571148153868">"शॉर्टकट निवडा"</string> + <string name="title_select_application" msgid="3280812711670683644">"अॅप निवडा"</string> + <string name="all_apps_button_label" msgid="9110807029020582876">"अॅप्स"</string> + <string name="all_apps_home_button_label" msgid="252062713717058851">"मुख्यपृष्ठ"</string> + <string name="delete_zone_label_workspace" msgid="4009607676751398685">"काढा"</string> + <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"विस्थापित करा"</string> + <string name="delete_target_label" msgid="1822697352535677073">"काढा"</string> + <string name="delete_target_uninstall_label" msgid="5100785476250872595">"विस्थापित करा"</string> + <string name="info_target_label" msgid="8053346143994679532">"अॅप माहिती"</string> + <string name="accessibility_search_button" msgid="1628520399424565142">"शोधा"</string> + <string name="accessibility_voice_search_button" msgid="4637324840434406584">"व्हॉइस शोध"</string> + <string name="accessibility_all_apps_button" msgid="2603132375383800483">"अॅप्स"</string> + <string name="accessibility_delete_button" msgid="6466114477993744621">"काढा"</string> + <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"अद्यतन विस्थापित करा"</string> + <string name="cab_menu_delete_app" msgid="7435191475867183689">"अॅप विस्थापित करा"</string> + <string name="cab_menu_app_info" msgid="8593722221450362342">"अॅप तपशील"</string> + <string name="cab_app_selection_text" msgid="374688303047985416">"1 अॅप निवडला"</string> + <string name="cab_widget_selection_text" msgid="1833458597831541241">"1 विजेट निवडले"</string> + <string name="cab_folder_selection_text" msgid="7999992513806132118">"1 फोल्डर निवडले"</string> + <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"1 शॉर्टकट निवडला"</string> + <string name="permlab_install_shortcut" msgid="5632423390354674437">"शॉर्टकट स्थापित करा"</string> + <string name="permdesc_install_shortcut" msgid="923466509822011139">"वापरकर्ता हस्तक्षेपाशिवाय शॉर्टकट जोडण्यास अॅप ला अनुमती देते."</string> + <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"शॉर्टकट विस्थापित करा"</string> + <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"वापरकर्ता हस्तक्षेपाशिवाय शॉर्टकट काढण्यास अॅप ला अनुमती देते."</string> + <string name="permlab_read_settings" msgid="1941457408239617576">"मुख्यपृष्ठ सेटिंग्ज आणि शॉर्टकट वाचा"</string> + <string name="permdesc_read_settings" msgid="5833423719057558387">"मुख्यपृष्ठातील सेटिंग्ज आणि शॉर्टकट वाचण्यास अॅप ला अनुमती देते."</string> + <string name="permlab_write_settings" msgid="3574213698004620587">"मुख्यपृष्ठ सेटिंग्ज आणि शॉर्टकट लिहा"</string> + <string name="permdesc_write_settings" msgid="5440712911516509985">"मुख्यपृष्ठातील सेटिंग्ज आणि शॉर्टकट बदलण्यास अॅप ला अनुमती देते."</string> + <string name="gadget_error_text" msgid="6081085226050792095">"विजेट लोड करण्यात समस्या"</string> + <string name="uninstall_system_app_text" msgid="4172046090762920660">"हा सिस्टम अॅप आहे आणि विस्थापित केला जाऊ शकत नाही."</string> + <string name="dream_name" msgid="1530253749244328964">"रॉकेट लाँचर"</string> + <string name="folder_hint_text" msgid="6617836969016293992">"अनामित फोल्डर"</string> + <string name="workspace_description_format" msgid="2950174241104043327">"मुख्य स्क्रीन %1$d"</string> + <string name="default_scroll_format" msgid="7475544710230993317">"%2$d पैकी %1$d पृष्ठ"</string> + <string name="workspace_scroll_format" msgid="8458889198184077399">"%2$d पैकी %1$d मुख्य स्क्रीन"</string> + <string name="apps_customize_apps_scroll_format" msgid="370005296147130238">"%2$d पैकी %1$d Apps पृष्ठ"</string> + <string name="apps_customize_widgets_scroll_format" msgid="3106209519974971521">"%2$d पैकी %1$d विजेट पृष्ठ"</string> + <string name="first_run_cling_title" msgid="2459738000155917941">"सुस्वागतम"</string> + <string name="first_run_cling_description" msgid="6447072552696253358">"जसे पाहिजे तसे वापरा."</string> + <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string> + <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string> + <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"अॅप्स आणि फोल्डरसाठी आणखी स्क्रीन तयार करा"</string> + <string name="migration_cling_title" msgid="9181776667882933767">"आपली अॅप चिन्हे कॉपी करा"</string> + <string name="migration_cling_description" msgid="2752413805582227644">"आपल्या जुन्या मुख्य स्क्रीनवरून चिन्हे आणि फोल्डर आयात करायची?"</string> + <string name="migration_cling_copy_apps" msgid="946331230090919440">"चिन्हे कॉपी करा"</string> + <string name="migration_cling_use_default" msgid="2626475813981258626">"नव्याने प्रारंभ करा"</string> + <string name="workspace_cling_title" msgid="5626202359865825661">"आपले स्थान व्यवस्थापित करा"</string> + <string name="workspace_cling_move_item" msgid="528201129978005352">"वॉलपेपर, विजेट आणि सेटिंग्ज व्यवस्थापित करण्यासाठी पार्श्वभूमीस स्पर्श करा आणि धरून ठेवा."</string> + <string name="folder_cling_title" msgid="3894908818693254164">"येथे एक फोल्डर आहे"</string> + <string name="folder_cling_create_folder" msgid="6158215559475836131">"यासारखे एखादे तयार करण्यासाठी अॅप ला स्पर्श करा आणि धरून ठेवा, नंतर तो दुसर्यावर हलवा."</string> + <string name="cling_dismiss" msgid="8962359497601507581">"ठीक"</string> + <string name="folder_opened" msgid="94695026776264709">"फोल्डर उघडले, <xliff:g id="WIDTH">%1$d</xliff:g> बाय <xliff:g id="HEIGHT">%2$d</xliff:g>"</string> + <string name="folder_tap_to_close" msgid="1884479294466410023">"फोल्डर बंद करण्यासाठी स्पर्श करा"</string> + <string name="folder_tap_to_rename" msgid="9191075570492871147">"नवे नाव जतन करण्यासाठी स्पर्श करा"</string> + <string name="folder_closed" msgid="4100806530910930934">"फोल्डर बंद"</string> + <string name="folder_renamed" msgid="1794088362165669656">"फोल्डरचे नाव बदलून <xliff:g id="NAME">%1$s</xliff:g> असे ठेवले"</string> + <string name="folder_name_format" msgid="6629239338071103179">"फोल्डर: <xliff:g id="NAME">%1$s</xliff:g>"</string> + <string name="widget_button_text" msgid="2880537293434387943">"विजेट"</string> + <string name="wallpaper_button_text" msgid="8404103075899945851">"वॉलपेपर"</string> + <string name="settings_button_text" msgid="8119458837558863227">"सेटिंग्ज"</string> + <string name="package_state_enqueued" msgid="6227252464303085641">"प्रतीक्षारत"</string> + <string name="package_state_downloading" msgid="4088770468458724721">"डाउनलोड करत आहे"</string> + <string name="package_state_installing" msgid="7588193972189849870">"स्थापित करत आहे"</string> + <string name="package_state_unknown" msgid="7592128424511031410">"अज्ञात"</string> + <string name="package_state_error" msgid="7672093962724223588">"पुनर्स्थापित झाले नाही"</string> + <string name="abandoned_clean_all" msgid="5256770727689657618">"सर्व काढा"</string> + <string name="abandoned_clean_this" msgid="7610119707847920412">"काढा"</string> + <string name="abandoned_search" msgid="891119232568284442">"शोधा"</string> + <string name="abandoned_promises_title" msgid="7096178467971716750">"हा अॅप स्थापित केलेला नाही"</string> + <string name="abandoned_promise_explanation" msgid="3990027586878167529">"या चिन्हासाठी अॅप स्थापित केलेला नाही. आपण ते काढू शकता किंवा अॅपचा शोध घेऊ शकता आणि त्यास व्यक्तिचलितपणे स्थापित करू शकता."</string> +</resources> diff --git a/res/values-ms-rMY/strings.xml b/res/values-ms-rMY/strings.xml index 678eeb46a..3c5876268 100644 --- a/res/values-ms-rMY/strings.xml +++ b/res/values-ms-rMY/strings.xml @@ -24,6 +24,7 @@ <string name="uid_name" msgid="7820867637514617527">"Apl Teras Android"</string> <string name="folder_name" msgid="7371454440695724752"></string> <string name="activity_not_found" msgid="8071924732094499514">"Apl tidak dipasang."</string> + <string name="safemode_shortcut_error" msgid="9160126848219158407">"Apl yang dimuat turun dilumpuhkan dalam mod Selamat"</string> <string name="widgets_tab_label" msgid="2921133187116603919">"Widget"</string> <string name="widget_adder" msgid="3201040140710381657">"Widget"</string> <string name="toggle_weight_watcher" msgid="5645299835184636119">"Papar Mem"</string> @@ -76,6 +77,7 @@ <string name="permlab_write_settings" msgid="3574213698004620587">"tulis tetapan dan pintasan Laman Utama"</string> <string name="permdesc_write_settings" msgid="5440712911516509985">"Membenarkan apl menukar tetapan dan pintasan di Laman Utama."</string> <string name="gadget_error_text" msgid="6081085226050792095">"Masalah memuatkan widget"</string> + <string name="gadget_setup_text" msgid="8274003207686040488">"Persediaan"</string> <string name="uninstall_system_app_text" msgid="4172046090762920660">"Ini ialah apl sistem dan tidak boleh dinyahpasang."</string> <string name="dream_name" msgid="1530253749244328964">"Pelancar Roket"</string> <string name="folder_hint_text" msgid="6617836969016293992">"Folder Tanpa Nama"</string> @@ -95,6 +97,9 @@ <string name="migration_cling_use_default" msgid="2626475813981258626">"MULAKAN YANG BAHARU"</string> <string name="workspace_cling_title" msgid="5626202359865825661">"Susun ruang anda"</string> <string name="workspace_cling_move_item" msgid="528201129978005352">"Sentuh & tahan latar belakang untuk mengurus kertas dinding, widget dan tetapan."</string> + <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Kertas dinding, widget & tetapan"</string> + <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"Sentuh & tahan latar belakang untuk memperibadikan"</string> + <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"FAHAM"</string> <string name="folder_cling_title" msgid="3894908818693254164">"Ini ada folder"</string> <string name="folder_cling_create_folder" msgid="6158215559475836131">"Untuk membuat satu folder seperti ini, sentuh & tahan apl, kemudian alihkan ke atas folder lain."</string> <string name="cling_dismiss" msgid="8962359497601507581">"OK"</string> @@ -107,4 +112,14 @@ <string name="widget_button_text" msgid="2880537293434387943">"Widget"</string> <string name="wallpaper_button_text" msgid="8404103075899945851">"Kertas dinding"</string> <string name="settings_button_text" msgid="8119458837558863227">"Tetapan"</string> + <string name="package_state_enqueued" msgid="6227252464303085641">"Menunggu"</string> + <string name="package_state_downloading" msgid="4088770468458724721">"Memuat turun"</string> + <string name="package_state_installing" msgid="7588193972189849870">"Memasang"</string> + <string name="package_state_unknown" msgid="7592128424511031410">"Tidak diketahui"</string> + <string name="package_state_error" msgid="7672093962724223588">"Tak dipulihkan"</string> + <string name="abandoned_clean_all" msgid="5256770727689657618">"Buang Semua"</string> + <string name="abandoned_clean_this" msgid="7610119707847920412">"Alih keluar"</string> + <string name="abandoned_search" msgid="891119232568284442">"Carian"</string> + <string name="abandoned_promises_title" msgid="7096178467971716750">"Apl ini tidak dipasang"</string> + <string name="abandoned_promise_explanation" msgid="3990027586878167529">"Apl untuk ikon ini tidak dipasang. Anda boleh mengalih keluar atau mencari dan memasang apl itu secara manual."</string> </resources> diff --git a/res/values-ms/strings.xml b/res/values-ms/strings.xml index d2f6bb142..f50a5db5b 100644 --- a/res/values-ms/strings.xml +++ b/res/values-ms/strings.xml @@ -41,7 +41,6 @@ <string name="group_applications" msgid="2103752818818161976">"Aplikasi"</string> <string name="group_shortcuts" msgid="9133529424900391877">"Pintasan"</string> <string name="group_widgets" msgid="6704978494073105844">"Widget"</string> - <string name="group_wallpapers" msgid="1568191644272224858">"Kertas dinding"</string> <string name="completely_out_of_space" msgid="1759078539443491182">"Tiada lagi ruang pada skrin Utama anda."</string> <string name="out_of_space" msgid="8365249326091984698">"Tiada lagi ruang pada skrin Utama ini"</string> <string name="hotseat_out_of_space" msgid="6304886797358479361">"Tiada lagi ruang pada kerusi panas."</string> diff --git a/res/values-my-rMM/strings.xml b/res/values-my-rMM/strings.xml new file mode 100644 index 000000000..8048b02a3 --- /dev/null +++ b/res/values-my-rMM/strings.xml @@ -0,0 +1,121 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +* Copyright (C) 2008 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. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="application_name" msgid="5181331383435256801">"Launcher၃"</string> + <string name="home" msgid="7658288663002113681">"ပင်မစာမျက်နှာ"</string> + <string name="uid_name" msgid="7820867637514617527">"Androidပင်မ အပ်ပလီကေးရှင်းများ"</string> + <string name="folder_name" msgid="7371454440695724752"></string> + <string name="activity_not_found" msgid="8071924732094499514">"အပ်ပလီကေးရှင်း မထည့်သွင်းထားပါ"</string> + <string name="safemode_shortcut_error" msgid="9160126848219158407">"ဒေါင်းလုဒ် appကို လုံခြုံရေး မုဒ်ထဲမှာ ပိတ်ထား"</string> + <string name="widgets_tab_label" msgid="2921133187116603919">"ဝဒ်ဂျက်များ"</string> + <string name="widget_adder" msgid="3201040140710381657">"ဝဒ်ဂျက်များ"</string> + <string name="toggle_weight_watcher" msgid="5645299835184636119">"Mem ကိုပြရန်"</string> + <string name="long_press_widget_to_add" msgid="7699152356777458215">"ဝဒ်ဂျက်တစ်ခုကို ကောက်ယူရန် ဖိနှိပ်ထားပါ"</string> + <string name="market" msgid="2619650989819296998">"စျေးဝယ်ရန်"</string> + <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string> + <string name="external_drop_widget_error" msgid="3165821058322217155">"ပင်မမျက်နှာစာတွင် အရာများ ချ လို့ မရတော့ပါ"</string> + <string name="external_drop_widget_pick_title" msgid="3486317258037690630">"ဝဒ်ဂျက်တစ်ခုအား ပြုဖန်တီးရန် ရွေးပါ"</string> + <string name="rename_folder_label" msgid="3727762225964550653">"အကန့်အမည်"</string> + <string name="rename_folder_title" msgid="3771389277707820891">"အကန့်အမည်ပြောင်းရန်"</string> + <string name="rename_action" msgid="5559600076028658757">"ကောင်းပြီ"</string> + <string name="cancel_action" msgid="7009134900002915310">"ပယ်ဖျက်သည်"</string> + <string name="menu_item_add_item" msgid="1264911265836810421">"ပင်မမျက်နှာစာသို့ ထည့်ပါ"</string> + <string name="group_applications" msgid="3797214114206693605">"အပ်ပလီကေးရှင်းများ"</string> + <string name="group_shortcuts" msgid="6012256992764410535">"အတိုကောက်မှတ်သားမှုများ"</string> + <string name="group_widgets" msgid="1569030723286851002">"ဝဒ်ဂျက်များ"</string> + <string name="completely_out_of_space" msgid="6106288382070760318">"ပင်မမျက်နှာစာတွင် နေရာလွတ် မကျန်တော့ပါ"</string> + <string name="out_of_space" msgid="4691004494942118364">"ဤပင်မမျက်နှာစာတွင် နေရာလွတ် မကျန်တော့ပါ"</string> + <string name="hotseat_out_of_space" msgid="7448809638125333693">"အနှစ်သက်ဆုံးများ ထားရာတွင် နေရာလွတ် မကျန်တော့ပါ"</string> + <string name="invalid_hotseat_item" msgid="5779907847267573691">"ဤဝဒ်ဂျက်မှာ အနှစ်သက်ဆုံးအရာများထားရာနေရာ အတွက် ကြီးလွန်းနေပါသည်"</string> + <string name="shortcut_installed" msgid="1701742129426969556">"အတိုကောက်မှတ်သားမှု \"<xliff:g id="NAME">%s</xliff:g>\" ကို ပြုလုပ်ပြီးပါပြီ"</string> + <string name="shortcut_uninstalled" msgid="8176767991305701821">"အတိုကောက်မှတ်သားမှု \"<xliff:g id="NAME">%s</xliff:g>\" ကို ဖယ်ရှားပြီးပါပြီ"</string> + <string name="shortcut_duplicate" msgid="9167217446062498127">"အတိုကောက်မှတ်သားမှု \"<xliff:g id="NAME">%s</xliff:g>\" ရှိပြီးသား ဖြစ်နေပါသည်"</string> + <string name="title_select_shortcut" msgid="6680642571148153868">"အတိုကောက်မှတ်သားမှုကို ရွေးရန်"</string> + <string name="title_select_application" msgid="3280812711670683644">"အပလီကေးရှင်း တစ်ခုခုကို ရွေးချယ်ပါ"</string> + <string name="all_apps_button_label" msgid="9110807029020582876">"အပ်ပလီကေးရှင်းများ"</string> + <string name="all_apps_home_button_label" msgid="252062713717058851">"ပင်မစာမျက်နှာ"</string> + <string name="delete_zone_label_workspace" msgid="4009607676751398685">"ဖယ်ရှာခြင်း"</string> + <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"ဖယ်ရှားခြင်း"</string> + <string name="delete_target_label" msgid="1822697352535677073">"ဖယ်ရှာခြင်း"</string> + <string name="delete_target_uninstall_label" msgid="5100785476250872595">"ဖယ်ရှားခြင်း"</string> + <string name="info_target_label" msgid="8053346143994679532">"အပ်ပလီကေးရှင်း အချက်အလက်များ"</string> + <string name="accessibility_search_button" msgid="1628520399424565142">"ရှာဖွေခြင်း"</string> + <string name="accessibility_voice_search_button" msgid="4637324840434406584">"အသံဖြင့် ရှာဖွေခြင်း"</string> + <string name="accessibility_all_apps_button" msgid="2603132375383800483">"အပ်ပလီကေးရှင်းများ"</string> + <string name="accessibility_delete_button" msgid="6466114477993744621">"ဖယ်ရှာခြင်း"</string> + <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"အဆင့်မြှင့်ခြင်းကို ဖယ်ရှားပါ"</string> + <string name="cab_menu_delete_app" msgid="7435191475867183689">"အပ်ပလီကေးရှင်းကို ဖယ်ရှားပါ"</string> + <string name="cab_menu_app_info" msgid="8593722221450362342">"အပ်ပလီကေးရှင်း အသေးစိတ် အချက်အလက်"</string> + <string name="cab_app_selection_text" msgid="374688303047985416">"အပ်ပလီကေးရှင်းတစ်ခု ရွေးချယ်ထားပြီး"</string> + <string name="cab_widget_selection_text" msgid="1833458597831541241">"ဝဒ်ဂျက်တစ်ခု ရွေးချယ်ထားပြီး"</string> + <string name="cab_folder_selection_text" msgid="7999992513806132118">"အကန့် တစ်ခု ရွေးချယ်ထားပြီး"</string> + <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"အတိုကောက်မှတ်သားမှုတစ်ခု ရွေးချယ်ထားပြီး"</string> + <string name="permlab_install_shortcut" msgid="5632423390354674437">"အတိုကောက်မှတ်သားမှုများအား ထည့်သွင်းခြင်း"</string> + <string name="permdesc_install_shortcut" msgid="923466509822011139">"အသုံးပြုသူ လုပ်ဆောင်မှုမရှိပဲ အပ်ပလီကေးရှင်းကို အတိုကောက်မှတ်သားမှုများ ပြုလုပ်ခွင့် ပေးခြင်း"</string> + <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"အတိုကောက်မှတ်သားမှုများ ဖယ်ထုတ်ခြင်း"</string> + <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"အပ်ပလီကေးရှင်းအား အသုံးပြုသူ မပါဝင်ပဲ အတိုကောက်မှတ်သားမှုများ ဖယ်ရှားခွင့် ပြုခြင်း"</string> + <string name="permlab_read_settings" msgid="1941457408239617576">"ပင်မမျက်နှာစာ အပြင်အဆင် နှင့် အတိုကောက်မှတ်သားမှုများအား ဖတ်ခြင်း"</string> + <string name="permdesc_read_settings" msgid="5833423719057558387">"ပင်မမျက်နှာစာတွင်ရှိသော အပြင်အဆင်နှင့် အတိုကောက်မှတ်သားမှုများကို အပ်ပလီကေးရှင်းအား ဖတ်ခွင့်ပြုခြင်း"</string> + <string name="permlab_write_settings" msgid="3574213698004620587">"ပင်မမျက်နှာစာ အပြင်အဆင် နှင့် အတိုကောက်မှတ်သားမှုများအား ရေးသားခြင်း"</string> + <string name="permdesc_write_settings" msgid="5440712911516509985">"ပင်မမျက်နှာစာတွင် ရှိသော အပြင်အဆင် နှင့် အတိုကောက်မှတ်သားမှုများ ကို အပ်ပလီကေးရှင်းအား ပြောင်းခွင့်ပြုခြင်း"</string> + <string name="gadget_error_text" msgid="6081085226050792095">"ဝဒ်ဂျက် တင်ရာတွင် ပြသနာ ရှိပါသည်"</string> + <string name="uninstall_system_app_text" msgid="4172046090762920660">"ဤအပ်ပလီကေးရှင်းမှာ စစ်စတန်ပိုင်းဆိုင်ရာ အပ်ပလီကေးရှင်းဖြစ်ပါသည်။ ထုတ်ပစ်၍ မရပါ"</string> + <string name="dream_name" msgid="1530253749244328964">"ဒုံပျံ ပစ်လွှတ်သောအရာ"</string> + <string name="folder_hint_text" msgid="6617836969016293992">"အမည်မရှိအကန့်"</string> + <string name="workspace_description_format" msgid="2950174241104043327">"ပင်မစာမျက်နှာ %1$d"</string> + <string name="default_scroll_format" msgid="7475544710230993317">"စာမျက်နှာ %1$d မှ %2$d"</string> + <string name="workspace_scroll_format" msgid="8458889198184077399">"ပင်မစာမျက်နှာ %1$d မှ %2$d"</string> + <string name="apps_customize_apps_scroll_format" msgid="370005296147130238">"အပ်ပလီကေးရှင်းပြ စာမျက်နှာ %1$d မှ %2$d"</string> + <string name="apps_customize_widgets_scroll_format" msgid="3106209519974971521">"ဝဒ်ဂျက်ပြ စာမျက်နှာ %1$d မှ %2$d"</string> + <string name="first_run_cling_title" msgid="2459738000155917941">"ကြိုဆိုပါသည်"</string> + <string name="first_run_cling_description" msgid="6447072552696253358">"ကိုယ့်အိမ်ကိုယ့်ယာလို သဘောထားပါ"</string> + <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string> + <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string> + <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"အပ်ပလီကေးရှင်း နှင့် အကန့်များအတွက် ဖန်သားပြင်မှာ ထပ်ထည့်ပါ"</string> + <string name="migration_cling_title" msgid="9181776667882933767">"အပ်ပလီကေးရှင်းပုံညွှန်းများကို ကူးယူပါ"</string> + <string name="migration_cling_description" msgid="2752413805582227644">"ပင်မစာမျက်နှာအဟောင်းမှ ပုံညွှန်းများ နှင့် အကန့်များကို ယူလာပါမလား"</string> + <string name="migration_cling_copy_apps" msgid="946331230090919440">"COPY ICONS"</string> + <string name="migration_cling_use_default" msgid="2626475813981258626">"START FRESH"</string> + <string name="workspace_cling_title" msgid="5626202359865825661">"စနစ်တကျဖြစ်အောင် ပြုလုပ်ပါ"</string> + <string name="workspace_cling_move_item" msgid="528201129978005352">"နောက်ခံကို ဖိကိုင်၍ နောက်ခံပုံ၊ဝဒ်ဂျက်များ၊အပြင်အဆင်များကို ထိန်းချုပ်ပါ"</string> + <string name="folder_cling_title" msgid="3894908818693254164">"ဒီမှာ အကန့်တစ်ခုဖြစ်ပါသည်"</string> + <string name="folder_cling_create_folder" msgid="6158215559475836131">"ဤကဲ့သို့လုပ်ရန်အတွက်၊ အပ်ပလီကေးရှင်းတစ်ခုကို ဖိကိုင်ပြီး နောက်တစ်ခုပေါ်သို့ ရွှေ့လိုက်ပါ"</string> + <string name="cling_dismiss" msgid="8962359497601507581">"ကောင်းပြီ"</string> + <string name="folder_opened" msgid="94695026776264709">"ဖွင့်ထားသောအကန့်, <xliff:g id="WIDTH">%1$d</xliff:g> နှင့် <xliff:g id="HEIGHT">%2$d</xliff:g>"</string> + <string name="folder_tap_to_close" msgid="1884479294466410023">"အကန့်ကို ပိတ်ရန် ဖိကိုင်ပါ"</string> + <string name="folder_tap_to_rename" msgid="9191075570492871147">"အမည်ပြောင်းခြင်း အတည်ပြုရန် ဖိကိုင်ပါ"</string> + <string name="folder_closed" msgid="4100806530910930934">"ပိတ်ထားသောအကန့်"</string> + <string name="folder_renamed" msgid="1794088362165669656">"ပြောင်းလဲလိုက်သော အကန့်အမည် <xliff:g id="NAME">%1$s</xliff:g>"</string> + <string name="folder_name_format" msgid="6629239338071103179">"အကန့်အမည်: <xliff:g id="NAME">%1$s</xliff:g>"</string> + <string name="widget_button_text" msgid="2880537293434387943">"ဝဒ်ဂျက်များ"</string> + <string name="wallpaper_button_text" msgid="8404103075899945851">"နောက်ခံများ"</string> + <string name="settings_button_text" msgid="8119458837558863227">"အပြင်အဆင်များ"</string> + <string name="package_state_enqueued" msgid="6227252464303085641">"စောင့်နေ"</string> + <string name="package_state_downloading" msgid="4088770468458724721">"ဒေါင်းလုဒ် လုပ်နေ"</string> + <string name="package_state_installing" msgid="7588193972189849870">"တပ်ဆင်နေ"</string> + <string name="package_state_unknown" msgid="7592128424511031410">"မသိရ"</string> + <string name="package_state_error" msgid="7672093962724223588">"ပြန်မဖေါ်ခဲ့"</string> + <string name="abandoned_clean_all" msgid="5256770727689657618">"အားလုံး ဖယ်ရှားရန်"</string> + <string name="abandoned_clean_this" msgid="7610119707847920412">"ဖယ်ရှားရန်"</string> + <string name="abandoned_search" msgid="891119232568284442">"ရှာဖွေရန်"</string> + <string name="abandoned_promises_title" msgid="7096178467971716750">"App မတပ်ဆင်ရသေးပါ"</string> + <string name="abandoned_promise_explanation" msgid="3990027586878167529">"ဤအိုင်ကွန်အတွက် app အားမထည့်သွင်းထားပါ။ You can remove it, or search for the app and install it manually."</string> +</resources> diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml index dd89a4f60..ff8280e73 100644 --- a/res/values-nb/strings.xml +++ b/res/values-nb/strings.xml @@ -24,6 +24,7 @@ <string name="uid_name" msgid="7820867637514617527">"Kjerneapper for Android"</string> <string name="folder_name" msgid="7371454440695724752"></string> <string name="activity_not_found" msgid="8071924732094499514">"Appen er ikke installert."</string> + <string name="safemode_shortcut_error" msgid="9160126848219158407">"En nedlastet app er deaktivert i sikker modus"</string> <string name="widgets_tab_label" msgid="2921133187116603919">"Moduler"</string> <string name="widget_adder" msgid="3201040140710381657">"Moduler"</string> <string name="toggle_weight_watcher" msgid="5645299835184636119">"Vis minne"</string> @@ -76,6 +77,7 @@ <string name="permlab_write_settings" msgid="3574213698004620587">"angi startsideinnstillinger og -snarveier"</string> <string name="permdesc_write_settings" msgid="5440712911516509985">"Lar appen endre innstillingene og snarveiene på startsiden."</string> <string name="gadget_error_text" msgid="6081085226050792095">"Problem ved innlasting av modul"</string> + <string name="gadget_setup_text" msgid="8274003207686040488">"Konfigurering"</string> <string name="uninstall_system_app_text" msgid="4172046090762920660">"Dette er en systemapp som ikke kan avinstalleres."</string> <string name="dream_name" msgid="1530253749244328964">"Rocket Launcher"</string> <string name="folder_hint_text" msgid="6617836969016293992">"Mappe uten navn"</string> @@ -95,6 +97,9 @@ <string name="migration_cling_use_default" msgid="2626475813981258626">"START PÅ NYTT"</string> <string name="workspace_cling_title" msgid="5626202359865825661">"Organiser plassen din"</string> <string name="workspace_cling_move_item" msgid="528201129978005352">"Trykk og hold på bakgrunnen for å administrere bakgrunnen, moduler og innstillinger."</string> + <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Bakgrunner, moduler og innstillinger"</string> + <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"Trykk og hold på bakgrunnen for å tilpasse den"</string> + <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"SKJØNNER"</string> <string name="folder_cling_title" msgid="3894908818693254164">"Dette er en mappe"</string> <string name="folder_cling_create_folder" msgid="6158215559475836131">"For å opprette en som denne, trykker og holder du på en app og flytter den over en annen."</string> <string name="cling_dismiss" msgid="8962359497601507581">"OK"</string> @@ -107,4 +112,14 @@ <string name="widget_button_text" msgid="2880537293434387943">"Moduler"</string> <string name="wallpaper_button_text" msgid="8404103075899945851">"Bakgrunner"</string> <string name="settings_button_text" msgid="8119458837558863227">"Innstillinger"</string> + <string name="package_state_enqueued" msgid="6227252464303085641">"Venter …"</string> + <string name="package_state_downloading" msgid="4088770468458724721">"Laster ned …"</string> + <string name="package_state_installing" msgid="7588193972189849870">"Installerer …"</string> + <string name="package_state_unknown" msgid="7592128424511031410">"Ukjent"</string> + <string name="package_state_error" msgid="7672093962724223588">"Ikke gjenoppr."</string> + <string name="abandoned_clean_all" msgid="5256770727689657618">"Fjern alle"</string> + <string name="abandoned_clean_this" msgid="7610119707847920412">"Fjern"</string> + <string name="abandoned_search" msgid="891119232568284442">"Søk"</string> + <string name="abandoned_promises_title" msgid="7096178467971716750">"Denne appen er ikke installert"</string> + <string name="abandoned_promise_explanation" msgid="3990027586878167529">"Appen for dette ikonet er ikke installert. Du kan fjerne det, eller prøve å søke etter appen og installere den manuelt."</string> </resources> diff --git a/res/values-ne-rNP/strings.xml b/res/values-ne-rNP/strings.xml new file mode 100644 index 000000000..fe75ea70d --- /dev/null +++ b/res/values-ne-rNP/strings.xml @@ -0,0 +1,124 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +* Copyright (C) 2008 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. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="application_name" msgid="5181331383435256801">"Launcher3"</string> + <string name="home" msgid="7658288663002113681">"गृह"</string> + <string name="uid_name" msgid="7820867637514617527">"Android मूल अनुप्रयोगहरू"</string> + <string name="folder_name" msgid="7371454440695724752"></string> + <string name="activity_not_found" msgid="8071924732094499514">"अनुप्रयोग स्थापित छैन।"</string> + <!-- no translation found for safemode_shortcut_error (9160126848219158407) --> + <skip /> + <string name="widgets_tab_label" msgid="2921133187116603919">"विजेटहरू"</string> + <string name="widget_adder" msgid="3201040140710381657">"विजेटहरू"</string> + <string name="toggle_weight_watcher" msgid="5645299835184636119">"Mem देखाउनुहोस्"</string> + <string name="long_press_widget_to_add" msgid="7699152356777458215">"एउटा विजेटलाई टिप्नको लागि टच गरेर होल्ड गर्नुहोस्।"</string> + <string name="market" msgid="2619650989819296998">"पसल"</string> + <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string> + <string name="external_drop_widget_error" msgid="3165821058322217155">"यो गृह स्क्रिनमा वस्तु खसाउन सकिँदैन।"</string> + <string name="external_drop_widget_pick_title" msgid="3486317258037690630">"सृजना गर्नको लागि विजेट छान्नुहोस्"</string> + <string name="rename_folder_label" msgid="3727762225964550653">"फोल्डरको नाम"</string> + <string name="rename_folder_title" msgid="3771389277707820891">"फोल्डरलाई पुनःनामाकरण गर्नुहोस्"</string> + <string name="rename_action" msgid="5559600076028658757">"ठिक छ"</string> + <string name="cancel_action" msgid="7009134900002915310">"रद्द गर्नुहोस्"</string> + <string name="menu_item_add_item" msgid="1264911265836810421">"गृह स्क्रिनमा थप्नुहोस्"</string> + <string name="group_applications" msgid="3797214114206693605">"अनुप्रयोगहरू"</string> + <string name="group_shortcuts" msgid="6012256992764410535">"सर्टकटहरू"</string> + <string name="group_widgets" msgid="1569030723286851002">"विजेटहरू"</string> + <string name="completely_out_of_space" msgid="6106288382070760318">"यो गृह स्क्रिनहरूमा कुनै थप ठाउँ छैन"</string> + <string name="out_of_space" msgid="4691004494942118364">"यो गृह स्क्रिनमा कुनै थप ठाउँ छैन।"</string> + <string name="hotseat_out_of_space" msgid="7448809638125333693">"मनपर्ने ट्रे अब कुनै ठाँउ छैन"</string> + <string name="invalid_hotseat_item" msgid="5779907847267573691">"यो विजेट मनपर्ने ट्रे को लागि निकै ठूलो छ"</string> + <string name="shortcut_installed" msgid="1701742129426969556">"सर्टकट \"<xliff:g id="NAME">%s</xliff:g>\" सिर्जित गरियो।"</string> + <string name="shortcut_uninstalled" msgid="8176767991305701821">"सर्टकट \"<xliff:g id="NAME">%s</xliff:g>\" हटाइयो।"</string> + <string name="shortcut_duplicate" msgid="9167217446062498127">"सर्टकट \"<xliff:g id="NAME">%s</xliff:g>\" पहिल्यै अवस्थित छ।"</string> + <string name="title_select_shortcut" msgid="6680642571148153868">"सर्टकट छान्नुहोस्"</string> + <string name="title_select_application" msgid="3280812711670683644">"अनुप्रयोग छनौट गर्नुहोस्"</string> + <string name="all_apps_button_label" msgid="9110807029020582876">"अनुप्रयोगहरू"</string> + <string name="all_apps_home_button_label" msgid="252062713717058851">"गृह"</string> + <string name="delete_zone_label_workspace" msgid="4009607676751398685">"हटाउनुहोस्"</string> + <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"हटाउनुहोस्"</string> + <string name="delete_target_label" msgid="1822697352535677073">"हटाउनुहोस्"</string> + <string name="delete_target_uninstall_label" msgid="5100785476250872595">"हटाउनुहोस्"</string> + <string name="info_target_label" msgid="8053346143994679532">"अनुप्रयोग जानकारी"</string> + <string name="accessibility_search_button" msgid="1628520399424565142">"खोज्नुहोस्"</string> + <string name="accessibility_voice_search_button" msgid="4637324840434406584">"ध्वनि खोज"</string> + <string name="accessibility_all_apps_button" msgid="2603132375383800483">"अनुप्रयोगहरू"</string> + <string name="accessibility_delete_button" msgid="6466114477993744621">"हटाउनुहोस्"</string> + <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"अद्यावधिक अस्थापित गर्नुहोस्"</string> + <string name="cab_menu_delete_app" msgid="7435191475867183689">"अनुप्रयोग अस्थापना गर्नुहोस्"</string> + <string name="cab_menu_app_info" msgid="8593722221450362342">"अनुप्रयोग विवरणहरु"</string> + <string name="cab_app_selection_text" msgid="374688303047985416">"१ अनुप्रयोग चयन गरियो"</string> + <string name="cab_widget_selection_text" msgid="1833458597831541241">"१ विजेट चयन गरियो"</string> + <string name="cab_folder_selection_text" msgid="7999992513806132118">"१ फोल्डर चयन गरियो"</string> + <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"१ सर्टकट चयन गरियो"</string> + <string name="permlab_install_shortcut" msgid="5632423390354674437">"सर्टकट स्थापना गर्नेहोस्"</string> + <string name="permdesc_install_shortcut" msgid="923466509822011139">"प्रयोगकर्ताको हस्तक्षेप बिना एउटा अनुप्रयोगलाई सर्टकटमा थप्नको लागि अनुमति दिनुहोस्।"</string> + <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"सर्टकटहरूको स्थापन रद्द गर्नुहोस्"</string> + <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"अनुप्रयोगलाई उपयोगकर्ताको हस्तक्षेप बिना सर्टकटहरूलाई हटाउन अनुमति दिनुहोस्।"</string> + <string name="permlab_read_settings" msgid="1941457408239617576">"गृह सेटिङहरू र सर्टकटहरू पढ्नुहोस्"</string> + <string name="permdesc_read_settings" msgid="5833423719057558387">"गृहमा एउटा अनुप्रयोगलाई सेटिङहरू र सर्टकटहरू पढ्न अनुमति दिनुहोस्।"</string> + <string name="permlab_write_settings" msgid="3574213698004620587">"गृह सेटिङहरू र सर्टकटहरू लेख्नुहोस्"</string> + <string name="permdesc_write_settings" msgid="5440712911516509985">"गृहमा एउटा अनुप्रयोगलाई सेटिङ र सर्टकट बदल्न अनुमति दिनुहोस्।"</string> + <string name="gadget_error_text" msgid="6081085226050792095">"समस्या लोडिङ गर्ने विजेट"</string> + <string name="uninstall_system_app_text" msgid="4172046090762920660">"यो प्रणाली अनुप्रयोग हो र यसलाई स्थापना रद्द गर्न सकिँदैन।"</string> + <string name="dream_name" msgid="1530253749244328964">"रकेट लन्चर"</string> + <string name="folder_hint_text" msgid="6617836969016293992">"बेनाम फोल्डर"</string> + <string name="workspace_description_format" msgid="2950174241104043327">"गृह स्क्रिन %1$d"</string> + <string name="default_scroll_format" msgid="7475544710230993317">"पृष्ठ %2$d को %1$d"</string> + <string name="workspace_scroll_format" msgid="8458889198184077399">"गृह स्क्रिन %2$d को %2$d"</string> + <string name="apps_customize_apps_scroll_format" msgid="370005296147130238">"अनुप्रयोग पृष्ठ %2$d को %1$d"</string> + <!-- String.format failed for translation --> + <!-- no translation found for apps_customize_widgets_scroll_format (3106209519974971521) --> + <skip /> + <string name="first_run_cling_title" msgid="2459738000155917941">"स्वागतम"</string> + <string name="first_run_cling_description" msgid="6447072552696253358">"गृह आरामसँग बस्नुहोस्"</string> + <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string> + <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string> + <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"अनुप्रयोगहरु र फोल्डरहरुलाई थप स्क्रीनहरु सिर्जना गर्नुहोस्"</string> + <string name="migration_cling_title" msgid="9181776667882933767">"तपाईँको अनुप्रयोग आईकनको प्रतिलिप गर्नुहोस्"</string> + <string name="migration_cling_description" msgid="2752413805582227644">"आफ्नो पुरानो गृह स्क्रीनबाट अाईकन र फोल्डरहरू आयात गर्नुहोस्?"</string> + <string name="migration_cling_copy_apps" msgid="946331230090919440">"ICONS प्रतिलिप गर्नुहोस्"</string> + <string name="migration_cling_use_default" msgid="2626475813981258626">"START FRESH"</string> + <string name="workspace_cling_title" msgid="5626202359865825661">"आफ्नो ठाउँ व्यवस्थापन गर्नुहोस्"</string> + <string name="workspace_cling_move_item" msgid="528201129978005352">"वालपेपर, विजेट र सेटिङ्स प्रबन्ध गर्न पृष्ठभूमिलाई टच गरेर होल्ड गर्नुहोस्।"</string> + <string name="folder_cling_title" msgid="3894908818693254164">"यहाँ एउटा फोल्डर छ"</string> + <string name="folder_cling_create_folder" msgid="6158215559475836131">"यस्तै एक किसिमका सिर्जना गर्न, अनुप्रयोगलाई टच गरेर होल्ड गर्नुहोस्, त्यसपछि यसलाई अर्को माथि सार्नुहोस्।"</string> + <string name="cling_dismiss" msgid="8962359497601507581">"ठिक छ"</string> + <string name="folder_opened" msgid="94695026776264709">"फोल्डर खुल्यो <xliff:g id="WIDTH">%1$d</xliff:g> बाट <xliff:g id="HEIGHT">%2$d</xliff:g>"</string> + <string name="folder_tap_to_close" msgid="1884479294466410023">"फोल्डर बन्द गर्नको लागि टच गर्नुहोस्"</string> + <string name="folder_tap_to_rename" msgid="9191075570492871147">"पुन: नामाकरण बचत गर्न टच गर्नुहोस्।"</string> + <string name="folder_closed" msgid="4100806530910930934">"फोल्डर बन्द भयो"</string> + <string name="folder_renamed" msgid="1794088362165669656">"फोल्डर <xliff:g id="NAME">%1$s</xliff:g> मा पुनःनामाकरण गरियो।"</string> + <string name="folder_name_format" msgid="6629239338071103179">"फोल्डर: <xliff:g id="NAME">%1$s</xliff:g>"</string> + <string name="widget_button_text" msgid="2880537293434387943">"विजेटहरू"</string> + <string name="wallpaper_button_text" msgid="8404103075899945851">"वालपेपरहरु"</string> + <string name="settings_button_text" msgid="8119458837558863227">"सेटिंङहरू"</string> + <string name="package_state_enqueued" msgid="6227252464303085641">"पर्खँदै"</string> + <string name="package_state_downloading" msgid="4088770468458724721">"डाउनलोड हुँदै"</string> + <string name="package_state_installing" msgid="7588193972189849870">"स्थापना गर्दै"</string> + <string name="package_state_unknown" msgid="7592128424511031410">"अज्ञात"</string> + <string name="package_state_error" msgid="7672093962724223588">"पुनर्स्थापित भएन"</string> + <string name="abandoned_clean_all" msgid="5256770727689657618">"सबै हटाउनुहोस्"</string> + <string name="abandoned_clean_this" msgid="7610119707847920412">"हटाउनुहोस्"</string> + <string name="abandoned_search" msgid="891119232568284442">"खोजी गर्नुहोस्"</string> + <string name="abandoned_promises_title" msgid="7096178467971716750">"यो अनुप्रयोग स्थापित छैन"</string> + <string name="abandoned_promise_explanation" msgid="3990027586878167529">"यो प्रतिमाका लागि अनुप्रयोगलाई स्थापना गरिएको छैन। तपाईँ यसलाई हटाउन, वा अनुप्रयोग खोजी र स्वयं यो स्थापित गर्न सक्नुहुन्छ।"</string> +</resources> diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml index d39c1ea11..470eb8722 100644 --- a/res/values-nl/strings.xml +++ b/res/values-nl/strings.xml @@ -24,6 +24,7 @@ <string name="uid_name" msgid="7820867637514617527">"Android-kernapps"</string> <string name="folder_name" msgid="7371454440695724752"></string> <string name="activity_not_found" msgid="8071924732094499514">"App is niet geïnstalleerd."</string> + <string name="safemode_shortcut_error" msgid="9160126848219158407">"Gedownloade app uitgeschakeld in veilige modus"</string> <string name="widgets_tab_label" msgid="2921133187116603919">"Widgets"</string> <string name="widget_adder" msgid="3201040140710381657">"Widgets"</string> <string name="toggle_weight_watcher" msgid="5645299835184636119">"Geheugen weergeven"</string> @@ -76,6 +77,7 @@ <string name="permlab_write_settings" msgid="3574213698004620587">"instellingen en snelkoppelingen op de startpagina schrijven"</string> <string name="permdesc_write_settings" msgid="5440712911516509985">"De app toestaan de instellingen en snelkoppelingen op de startpagina te wijzigen."</string> <string name="gadget_error_text" msgid="6081085226050792095">"Probleem bij het laden van widget"</string> + <string name="gadget_setup_text" msgid="8274003207686040488">"Configuratie"</string> <string name="uninstall_system_app_text" msgid="4172046090762920660">"Dit is een systeemapp die niet kan worden verwijderd."</string> <string name="dream_name" msgid="1530253749244328964">"Rocket Launcher"</string> <string name="folder_hint_text" msgid="6617836969016293992">"Naamloze map"</string> @@ -95,6 +97,9 @@ <string name="migration_cling_use_default" msgid="2626475813981258626">"OPNIEUW BEGINNEN"</string> <string name="workspace_cling_title" msgid="5626202359865825661">"Uw ruimte indelen"</string> <string name="workspace_cling_move_item" msgid="528201129978005352">"Blijf de achtergrond aanraken om de achtergrond, widgets en instellingen te beheren."</string> + <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Achtergronden, widgets en instellingen"</string> + <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"Blijf de achtergrond aanraken om deze aan te passen"</string> + <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"OK"</string> <string name="folder_cling_title" msgid="3894908818693254164">"Dit is een map"</string> <string name="folder_cling_create_folder" msgid="6158215559475836131">"Als u een map zoals deze wilt maken, blijft u een app aanraken en schuift u deze boven op een andere app."</string> <string name="cling_dismiss" msgid="8962359497601507581">"OK"</string> @@ -107,4 +112,14 @@ <string name="widget_button_text" msgid="2880537293434387943">"Widgets"</string> <string name="wallpaper_button_text" msgid="8404103075899945851">"Achtergronden"</string> <string name="settings_button_text" msgid="8119458837558863227">"Instellingen"</string> + <string name="package_state_enqueued" msgid="6227252464303085641">"Wachten"</string> + <string name="package_state_downloading" msgid="4088770468458724721">"Downloaden"</string> + <string name="package_state_installing" msgid="7588193972189849870">"Installeren"</string> + <string name="package_state_unknown" msgid="7592128424511031410">"Onbekend"</string> + <string name="package_state_error" msgid="7672093962724223588">"Niet hersteld"</string> + <string name="abandoned_clean_all" msgid="5256770727689657618">"Alles verwijderen"</string> + <string name="abandoned_clean_this" msgid="7610119707847920412">"Verwijderen"</string> + <string name="abandoned_search" msgid="891119232568284442">"Zoeken"</string> + <string name="abandoned_promises_title" msgid="7096178467971716750">"Deze app is niet geïnstalleerd"</string> + <string name="abandoned_promise_explanation" msgid="3990027586878167529">"De app voor dit pictogram is niet geïnstalleerd. U kunt het pictogram verwijderen of de app zoeken en handmatig installeren."</string> </resources> diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml index b428a95ca..61a51e0a5 100644 --- a/res/values-pl/strings.xml +++ b/res/values-pl/strings.xml @@ -24,6 +24,7 @@ <string name="uid_name" msgid="7820867637514617527">"Główne aplikacje Androida"</string> <string name="folder_name" msgid="7371454440695724752"></string> <string name="activity_not_found" msgid="8071924732094499514">"Aplikacja nie jest zainstalowana."</string> + <string name="safemode_shortcut_error" msgid="9160126848219158407">"Pobrana aplikacja została wyłączona w trybie awaryjnym"</string> <string name="widgets_tab_label" msgid="2921133187116603919">"Widżety"</string> <string name="widget_adder" msgid="3201040140710381657">"Widżety"</string> <string name="toggle_weight_watcher" msgid="5645299835184636119">"Pokaż pamięć"</string> @@ -76,6 +77,7 @@ <string name="permlab_write_settings" msgid="3574213698004620587">"zapisywanie ustawień i skrótów na ekranie głównym"</string> <string name="permdesc_write_settings" msgid="5440712911516509985">"Umożliwia aplikacji zmianę ustawień i skrótów na ekranie głównym."</string> <string name="gadget_error_text" msgid="6081085226050792095">"Problem podczas ładowania widżetu"</string> + <string name="gadget_setup_text" msgid="8274003207686040488">"Konfiguracja"</string> <string name="uninstall_system_app_text" msgid="4172046090762920660">"To aplikacja systemowa i nie można jej odinstalować."</string> <string name="dream_name" msgid="1530253749244328964">"Wyrzutnia rakiet"</string> <string name="folder_hint_text" msgid="6617836969016293992">"Folder bez nazwy"</string> @@ -95,6 +97,9 @@ <string name="migration_cling_use_default" msgid="2626475813981258626">"ZACZNIJ OD NOWA"</string> <string name="workspace_cling_title" msgid="5626202359865825661">"Uporządkuj obszar roboczy"</string> <string name="workspace_cling_move_item" msgid="528201129978005352">"Kliknij i przytrzymaj tło, by zmienić tapetę, widżety lub ustawienia."</string> + <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Tapety, widżety i ustawienia"</string> + <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"Kliknij i przytrzymaj tło, by dostosować"</string> + <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"OK"</string> <string name="folder_cling_title" msgid="3894908818693254164">"Tu jest folder"</string> <string name="folder_cling_create_folder" msgid="6158215559475836131">"Aby utworzyć taki sam, kliknij i przytrzymaj aplikację, a następnie przenieś ją na następną."</string> <string name="cling_dismiss" msgid="8962359497601507581">"OK"</string> @@ -107,4 +112,14 @@ <string name="widget_button_text" msgid="2880537293434387943">"Widżety"</string> <string name="wallpaper_button_text" msgid="8404103075899945851">"Tapety"</string> <string name="settings_button_text" msgid="8119458837558863227">"Ustawienia"</string> + <string name="package_state_enqueued" msgid="6227252464303085641">"Oczekiwanie"</string> + <string name="package_state_downloading" msgid="4088770468458724721">"Pobieranie"</string> + <string name="package_state_installing" msgid="7588193972189849870">"Instalowanie"</string> + <string name="package_state_unknown" msgid="7592128424511031410">"Brak informacji"</string> + <string name="package_state_error" msgid="7672093962724223588">"Nie przywrócono"</string> + <string name="abandoned_clean_all" msgid="5256770727689657618">"Usuń wszystkie"</string> + <string name="abandoned_clean_this" msgid="7610119707847920412">"Usuń"</string> + <string name="abandoned_search" msgid="891119232568284442">"Szukaj"</string> + <string name="abandoned_promises_title" msgid="7096178467971716750">"Ta aplikacja nie jest zainstalowana"</string> + <string name="abandoned_promise_explanation" msgid="3990027586878167529">"Aplikacja, której odpowiada ta ikona, nie jest zainstalowana. Możesz usunąć ikonę lub wyszukać aplikację i zainstalować ją ręcznie."</string> </resources> diff --git a/res/values-port/dimens.xml b/res/values-port/dimens.xml index 7753ab318..c20f57b2b 100644 --- a/res/values-port/dimens.xml +++ b/res/values-port/dimens.xml @@ -16,9 +16,6 @@ <resources> <!-- AppsCustomize --> - <integer name="apps_customize_cling_focused_x">1</integer> - <integer name="apps_customize_cling_focused_y">1</integer> - <integer name="apps_customize_widget_cell_count_x">2</integer> <integer name="apps_customize_widget_cell_count_y">3</integer> </resources> diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml index b8e51d6d2..2fe062a4a 100644 --- a/res/values-pt-rPT/strings.xml +++ b/res/values-pt-rPT/strings.xml @@ -24,6 +24,7 @@ <string name="uid_name" msgid="7820867637514617527">"Aplicações principais do Android"</string> <string name="folder_name" msgid="7371454440695724752"></string> <string name="activity_not_found" msgid="8071924732094499514">"A aplicação não está instalada."</string> + <string name="safemode_shortcut_error" msgid="9160126848219158407">"Aplicação transferida desativada no Modo de segurança"</string> <string name="widgets_tab_label" msgid="2921133187116603919">"Widgets"</string> <string name="widget_adder" msgid="3201040140710381657">"Widgets"</string> <string name="toggle_weight_watcher" msgid="5645299835184636119">"Mostrar mem"</string> @@ -76,6 +77,7 @@ <string name="permlab_write_settings" msgid="3574213698004620587">"escrever definições e atalhos do Ecrã principal"</string> <string name="permdesc_write_settings" msgid="5440712911516509985">"Permite à aplicação alterar as definições e os atalhos no Ecrã Principal."</string> <string name="gadget_error_text" msgid="6081085226050792095">"Problema ao carregar o widget"</string> + <string name="gadget_setup_text" msgid="8274003207686040488">"Configuração"</string> <string name="uninstall_system_app_text" msgid="4172046090762920660">"É uma aplicação de sistema e não pode ser desinstalada."</string> <string name="dream_name" msgid="1530253749244328964">"Lança-mísseis"</string> <string name="folder_hint_text" msgid="6617836969016293992">"Pasta sem nome"</string> @@ -95,6 +97,9 @@ <string name="migration_cling_use_default" msgid="2626475813981258626">"COMEÇAR DO INÍCIO"</string> <string name="workspace_cling_title" msgid="5626202359865825661">"Organizar o seu espaço"</string> <string name="workspace_cling_move_item" msgid="528201129978005352">"Toque sem soltar no fundo para gerir a imagem de fundo, os widgets e as definições."</string> + <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Imagens de fundo, widgets e definições"</string> + <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"Toque sem soltar no fundo para personalizar"</string> + <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"COMPREENDI"</string> <string name="folder_cling_title" msgid="3894908818693254164">"Eis uma pasta"</string> <string name="folder_cling_create_folder" msgid="6158215559475836131">"Para criar uma pasta, toque sem soltar numa aplicação e arraste-a para cima de outra aplicação."</string> <string name="cling_dismiss" msgid="8962359497601507581">"OK"</string> @@ -107,4 +112,14 @@ <string name="widget_button_text" msgid="2880537293434387943">"Widgets"</string> <string name="wallpaper_button_text" msgid="8404103075899945851">"Imagens de fundo"</string> <string name="settings_button_text" msgid="8119458837558863227">"Definições"</string> + <string name="package_state_enqueued" msgid="6227252464303085641">"A aguardar"</string> + <string name="package_state_downloading" msgid="4088770468458724721">"A transferir "</string> + <string name="package_state_installing" msgid="7588193972189849870">"A instalar"</string> + <string name="package_state_unknown" msgid="7592128424511031410">"Desconhecido"</string> + <string name="package_state_error" msgid="7672093962724223588">"Não restaurado"</string> + <string name="abandoned_clean_all" msgid="5256770727689657618">"Remover todos"</string> + <string name="abandoned_clean_this" msgid="7610119707847920412">"Remover"</string> + <string name="abandoned_search" msgid="891119232568284442">"Pesquisar"</string> + <string name="abandoned_promises_title" msgid="7096178467971716750">"Esta aplicação não está instalada"</string> + <string name="abandoned_promise_explanation" msgid="3990027586878167529">"A aplicação deste ícone não está instalada. Pode removê-lo ou pesquisar a aplicação e instalá-la manualmente."</string> </resources> diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml index 03c621af2..ddbb25310 100644 --- a/res/values-pt/strings.xml +++ b/res/values-pt/strings.xml @@ -21,9 +21,10 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="application_name" msgid="5181331383435256801">"Launcher3"</string> <string name="home" msgid="7658288663002113681">"Início"</string> - <string name="uid_name" msgid="7820867637514617527">"Principais aplicativos do Android"</string> + <string name="uid_name" msgid="7820867637514617527">"Principais apps do Android"</string> <string name="folder_name" msgid="7371454440695724752"></string> - <string name="activity_not_found" msgid="8071924732094499514">"O aplicativo não está instalado."</string> + <string name="activity_not_found" msgid="8071924732094499514">"O app não está instalado."</string> + <string name="safemode_shortcut_error" msgid="9160126848219158407">"App transferido por download desativado no modo de segurança"</string> <string name="widgets_tab_label" msgid="2921133187116603919">"Widgets"</string> <string name="widget_adder" msgid="3201040140710381657">"Widgets"</string> <string name="toggle_weight_watcher" msgid="5645299835184636119">"Mostrar memória"</string> @@ -37,7 +38,7 @@ <string name="rename_action" msgid="5559600076028658757">"Ok"</string> <string name="cancel_action" msgid="7009134900002915310">"Cancelar"</string> <string name="menu_item_add_item" msgid="1264911265836810421">"Adicionar à tela inicial"</string> - <string name="group_applications" msgid="3797214114206693605">"Aplicativos"</string> + <string name="group_applications" msgid="3797214114206693605">"Apps"</string> <string name="group_shortcuts" msgid="6012256992764410535">"Atalhos"</string> <string name="group_widgets" msgid="1569030723286851002">"Widgets"</string> <string name="completely_out_of_space" msgid="6106288382070760318">"Não há mais espaço nas telas iniciais."</string> @@ -48,55 +49,59 @@ <string name="shortcut_uninstalled" msgid="8176767991305701821">"O atalho \"<xliff:g id="NAME">%s</xliff:g>\" foi removido."</string> <string name="shortcut_duplicate" msgid="9167217446062498127">"O atalho \"<xliff:g id="NAME">%s</xliff:g>\" já existe."</string> <string name="title_select_shortcut" msgid="6680642571148153868">"Selecione um atalho"</string> - <string name="title_select_application" msgid="3280812711670683644">"Selecione um aplicativo"</string> - <string name="all_apps_button_label" msgid="9110807029020582876">"Aplicativos"</string> + <string name="title_select_application" msgid="3280812711670683644">"Selecione um app"</string> + <string name="all_apps_button_label" msgid="9110807029020582876">"Apps"</string> <string name="all_apps_home_button_label" msgid="252062713717058851">"Início"</string> <string name="delete_zone_label_workspace" msgid="4009607676751398685">"Remover"</string> <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"Desinstalar"</string> <string name="delete_target_label" msgid="1822697352535677073">"Remover"</string> <string name="delete_target_uninstall_label" msgid="5100785476250872595">"Desinstalar"</string> - <string name="info_target_label" msgid="8053346143994679532">"Informações do aplicativo"</string> + <string name="info_target_label" msgid="8053346143994679532">"Informações do app"</string> <string name="accessibility_search_button" msgid="1628520399424565142">"Pesquisar"</string> <string name="accessibility_voice_search_button" msgid="4637324840434406584">"Pesquisa por voz"</string> - <string name="accessibility_all_apps_button" msgid="2603132375383800483">"Aplicativos"</string> + <string name="accessibility_all_apps_button" msgid="2603132375383800483">"Apps"</string> <string name="accessibility_delete_button" msgid="6466114477993744621">"Remover"</string> <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"Desinstalar atualização"</string> - <string name="cab_menu_delete_app" msgid="7435191475867183689">"Desinstalar aplicativo"</string> - <string name="cab_menu_app_info" msgid="8593722221450362342">"Detalhes do aplicativo"</string> - <string name="cab_app_selection_text" msgid="374688303047985416">"Um aplicativo selecionado"</string> + <string name="cab_menu_delete_app" msgid="7435191475867183689">"Desinstalar app"</string> + <string name="cab_menu_app_info" msgid="8593722221450362342">"Detalhes do app"</string> + <string name="cab_app_selection_text" msgid="374688303047985416">"Um app selecionado"</string> <string name="cab_widget_selection_text" msgid="1833458597831541241">"Um widget selecionado"</string> <string name="cab_folder_selection_text" msgid="7999992513806132118">"Uma pasta selecionada"</string> <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"Um atalho selecionado"</string> <string name="permlab_install_shortcut" msgid="5632423390354674437">"instalar atalhos"</string> - <string name="permdesc_install_shortcut" msgid="923466509822011139">"Permite que um aplicativo adicione atalhos sem intervenção do usuário."</string> + <string name="permdesc_install_shortcut" msgid="923466509822011139">"Permite que um app adicione atalhos sem intervenção do usuário."</string> <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"desinstalar atalhos"</string> - <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"Permite que o aplicativo remova atalhos sem a intervenção do usuário."</string> + <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"Permite que o app remova atalhos sem a intervenção do usuário."</string> <string name="permlab_read_settings" msgid="1941457408239617576">"ler configurações e atalhos da tela inicial"</string> - <string name="permdesc_read_settings" msgid="5833423719057558387">"Permite que o aplicativo leia as configurações e os atalhos na tela inicial."</string> + <string name="permdesc_read_settings" msgid="5833423719057558387">"Permite que o app leia as configurações e os atalhos na tela inicial."</string> <string name="permlab_write_settings" msgid="3574213698004620587">"gravar configurações e atalhos da tela inicial"</string> - <string name="permdesc_write_settings" msgid="5440712911516509985">"Permite que o aplicativo altere as configurações e os atalhos na tela inicial."</string> + <string name="permdesc_write_settings" msgid="5440712911516509985">"Permite que o app altere as configurações e os atalhos na tela inicial."</string> <string name="gadget_error_text" msgid="6081085226050792095">"Problema ao carregar o widget"</string> - <string name="uninstall_system_app_text" msgid="4172046090762920660">"Este é um aplicativo do sistema e não pode ser desinstalado."</string> + <string name="gadget_setup_text" msgid="8274003207686040488">"Configuração"</string> + <string name="uninstall_system_app_text" msgid="4172046090762920660">"Este é um app do sistema e não pode ser desinstalado."</string> <string name="dream_name" msgid="1530253749244328964">"Rocket Launcher"</string> <string name="folder_hint_text" msgid="6617836969016293992">"Pasta sem nome"</string> <string name="workspace_description_format" msgid="2950174241104043327">"Tela inicial %1$d"</string> <string name="default_scroll_format" msgid="7475544710230993317">"Página %1$d de %2$d"</string> <string name="workspace_scroll_format" msgid="8458889198184077399">"Tela inicial %1$d de %2$d"</string> - <string name="apps_customize_apps_scroll_format" msgid="370005296147130238">"Página de aplicativos, %1$d de %2$d"</string> + <string name="apps_customize_apps_scroll_format" msgid="370005296147130238">"Página de apps, %1$d de %2$d"</string> <string name="apps_customize_widgets_scroll_format" msgid="3106209519974971521">"Página de widgets, %1$d de %2$d"</string> <string name="first_run_cling_title" msgid="2459738000155917941">"Bem-vindo"</string> <string name="first_run_cling_description" msgid="6447072552696253358">"Fique à vontade."</string> <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string> <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string> - <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"Crie mais telas para aplicativos e pastas"</string> - <string name="migration_cling_title" msgid="9181776667882933767">"Copiar ícones de aplicativos"</string> + <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"Crie mais telas para apps e pastas"</string> + <string name="migration_cling_title" msgid="9181776667882933767">"Copiar ícones de apps"</string> <string name="migration_cling_description" msgid="2752413805582227644">"Importar ícones e pastas de suas telas iniciais antigas?"</string> <string name="migration_cling_copy_apps" msgid="946331230090919440">"COPIAR ÍCONES"</string> <string name="migration_cling_use_default" msgid="2626475813981258626">"COMEÇAR DO ZERO"</string> <string name="workspace_cling_title" msgid="5626202359865825661">"Organize seu espaço"</string> <string name="workspace_cling_move_item" msgid="528201129978005352">"Toque e mantenha pressionada a tela de fundo para gerenciar o plano de fundo, os widgets e as configurações."</string> + <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Plano de fundo, widgets e configurações"</string> + <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"Toque e mantenha pressionado o segundo plano para personalizar"</string> + <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"ENTENDI"</string> <string name="folder_cling_title" msgid="3894908818693254164">"Aqui está uma pasta"</string> - <string name="folder_cling_create_folder" msgid="6158215559475836131">"Para criar uma pasta como esta, mantenha pressionado um aplicativo e mova-o para cima de outro."</string> + <string name="folder_cling_create_folder" msgid="6158215559475836131">"Para criar uma pasta como esta, mantenha pressionado um app e mova-o para cima de outro."</string> <string name="cling_dismiss" msgid="8962359497601507581">"Ok"</string> <string name="folder_opened" msgid="94695026776264709">"Pasta aberta, <xliff:g id="WIDTH">%1$d</xliff:g> por <xliff:g id="HEIGHT">%2$d</xliff:g>"</string> <string name="folder_tap_to_close" msgid="1884479294466410023">"Toque para fechar a pasta"</string> @@ -107,4 +112,14 @@ <string name="widget_button_text" msgid="2880537293434387943">"Widgets"</string> <string name="wallpaper_button_text" msgid="8404103075899945851">"Planos de fundo"</string> <string name="settings_button_text" msgid="8119458837558863227">"Configurações"</string> + <string name="package_state_enqueued" msgid="6227252464303085641">"Aguardando"</string> + <string name="package_state_downloading" msgid="4088770468458724721">"Transferindo"</string> + <string name="package_state_installing" msgid="7588193972189849870">"Instalando"</string> + <string name="package_state_unknown" msgid="7592128424511031410">"Desconhecido"</string> + <string name="package_state_error" msgid="7672093962724223588">"Não restaurado"</string> + <string name="abandoned_clean_all" msgid="5256770727689657618">"Remover tudo"</string> + <string name="abandoned_clean_this" msgid="7610119707847920412">"Remover"</string> + <string name="abandoned_search" msgid="891119232568284442">"Pesquisar"</string> + <string name="abandoned_promises_title" msgid="7096178467971716750">"Este app não está instalado"</string> + <string name="abandoned_promise_explanation" msgid="3990027586878167529">"O app deste ícone não está instalado. Você pode remover o ícone, ou procurar o app e instalá-lo manualmente."</string> </resources> diff --git a/res/values-rm/strings.xml b/res/values-rm/strings.xml index 36000956f..be35c6b09 100644 --- a/res/values-rm/strings.xml +++ b/res/values-rm/strings.xml @@ -192,4 +192,14 @@ <skip /> <!-- no translation found for settings_button_text (8119458837558863227) --> <skip /> + <!-- no translation found for package_state_enqueued (6227252464303085641) --> + <skip /> + <!-- no translation found for package_state_downloading (4088770468458724721) --> + <skip /> + <!-- no translation found for package_state_installing (7588193972189849870) --> + <skip /> + <!-- no translation found for package_state_unknown (7592128424511031410) --> + <skip /> + <!-- no translation found for package_state_error (7672093962724223588) --> + <skip /> </resources> diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml index a667ffdc5..04aebc8b9 100644 --- a/res/values-ro/strings.xml +++ b/res/values-ro/strings.xml @@ -24,6 +24,7 @@ <string name="uid_name" msgid="7820867637514617527">"Android Core Apps"</string> <string name="folder_name" msgid="7371454440695724752"></string> <string name="activity_not_found" msgid="8071924732094499514">"Aplicația nu este instalată."</string> + <string name="safemode_shortcut_error" msgid="9160126848219158407">"Aplicația descărcată este dezactivată în modul de siguranță"</string> <string name="widgets_tab_label" msgid="2921133187116603919">"Widgeturi"</string> <string name="widget_adder" msgid="3201040140710381657">"Widgeturi"</string> <string name="toggle_weight_watcher" msgid="5645299835184636119">"Afișați memoria"</string> @@ -76,6 +77,7 @@ <string name="permlab_write_settings" msgid="3574213698004620587">"scrie setări și comenzi rapide pentru ecranul de pornire"</string> <string name="permdesc_write_settings" msgid="5440712911516509985">"Permite aplicației să modifice setările și comenzile rapide din ecranul de pornire."</string> <string name="gadget_error_text" msgid="6081085226050792095">"Problemă la încărcarea widgetului"</string> + <string name="gadget_setup_text" msgid="8274003207686040488">"Configurați"</string> <string name="uninstall_system_app_text" msgid="4172046090762920660">"Aceasta este o aplicație de sistem și nu poate fi dezinstalată."</string> <string name="dream_name" msgid="1530253749244328964">"Rocket Launcher"</string> <string name="folder_hint_text" msgid="6617836969016293992">"Dosar fără nume"</string> @@ -95,6 +97,9 @@ <string name="migration_cling_use_default" msgid="2626475813981258626">"REÎNCEPEȚI"</string> <string name="workspace_cling_title" msgid="5626202359865825661">"Organizați-vă spațiul"</string> <string name="workspace_cling_move_item" msgid="528201129978005352">"Atingeți lung fundalul pentru a gestiona imaginea de fundal, widgeturile și setările."</string> + <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Imagini de fundal, widgeturi și setări"</string> + <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"Atingeți lung fundalul pentru a-l personaliza"</string> + <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"AM ÎNȚELES"</string> <string name="folder_cling_title" msgid="3894908818693254164">"Iată un dosar"</string> <string name="folder_cling_create_folder" msgid="6158215559475836131">"Pentru a crea un dosar similar, atingeți și țineți degetul pe o aplicație, apoi mutați-o deasupra alteia."</string> <string name="cling_dismiss" msgid="8962359497601507581">"OK"</string> @@ -107,4 +112,14 @@ <string name="widget_button_text" msgid="2880537293434387943">"Widgeturi"</string> <string name="wallpaper_button_text" msgid="8404103075899945851">"Imagini de fundal"</string> <string name="settings_button_text" msgid="8119458837558863227">"Setări"</string> + <string name="package_state_enqueued" msgid="6227252464303085641">"În așteptare"</string> + <string name="package_state_downloading" msgid="4088770468458724721">"Se descarcă"</string> + <string name="package_state_installing" msgid="7588193972189849870">"Se instalează"</string> + <string name="package_state_unknown" msgid="7592128424511031410">"Necunoscut"</string> + <string name="package_state_error" msgid="7672093962724223588">"Nerestabilit"</string> + <string name="abandoned_clean_all" msgid="5256770727689657618">"Eliminați-le pe toate"</string> + <string name="abandoned_clean_this" msgid="7610119707847920412">"Eliminați"</string> + <string name="abandoned_search" msgid="891119232568284442">"Căutați"</string> + <string name="abandoned_promises_title" msgid="7096178467971716750">"Aplicația nu este instalată"</string> + <string name="abandoned_promise_explanation" msgid="3990027586878167529">"Aplicația pentru această pictogramă nu este instalată. Puteți să ștergeți pictograma sau să căutați aplicația și s-o instalați manual."</string> </resources> diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml index c2e8bc718..b1d7713a0 100644 --- a/res/values-ru/strings.xml +++ b/res/values-ru/strings.xml @@ -24,6 +24,7 @@ <string name="uid_name" msgid="7820867637514617527">"Основные приложения Android"</string> <string name="folder_name" msgid="7371454440695724752"></string> <string name="activity_not_found" msgid="8071924732094499514">"Приложение удалено"</string> + <string name="safemode_shortcut_error" msgid="9160126848219158407">"Скачанное приложение отключено в безопасном режиме"</string> <string name="widgets_tab_label" msgid="2921133187116603919">"Виджеты"</string> <string name="widget_adder" msgid="3201040140710381657">"Виджеты"</string> <string name="toggle_weight_watcher" msgid="5645299835184636119">"Сведения о памяти"</string> @@ -76,6 +77,7 @@ <string name="permlab_write_settings" msgid="3574213698004620587">"Изменение настроек и ярлыков главного экрана"</string> <string name="permdesc_write_settings" msgid="5440712911516509985">"Приложение сможет изменять настройки и ярлыки на главном экране."</string> <string name="gadget_error_text" msgid="6081085226050792095">"Не удалось загрузить виджет"</string> + <string name="gadget_setup_text" msgid="8274003207686040488">"Настройка"</string> <string name="uninstall_system_app_text" msgid="4172046090762920660">"Это системное приложение, его нельзя удалить."</string> <string name="dream_name" msgid="1530253749244328964">"Rocket Launcher"</string> <string name="folder_hint_text" msgid="6617836969016293992">"Папка без названия"</string> @@ -95,6 +97,9 @@ <string name="migration_cling_use_default" msgid="2626475813981258626">"ИСПОЛЬЗОВАТЬ СТАНДАРТНЫЙ МАКЕТ"</string> <string name="workspace_cling_title" msgid="5626202359865825661">"Организация рабочего пространства"</string> <string name="workspace_cling_move_item" msgid="528201129978005352">"Чтобы перейти к управлению обоями, виджетами и настройками, нажмите на фоновое изображение и удерживайте его."</string> + <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Обои, виджеты и настройки"</string> + <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"Чтобы выполнить настройку, коснитесь фона и удерживайте его"</string> + <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"ОК"</string> <string name="folder_cling_title" msgid="3894908818693254164">"Это папка"</string> <string name="folder_cling_create_folder" msgid="6158215559475836131">"Чтобы создать папку, нажмите и удерживайте значок приложения, а затем перетащите его на другой значок."</string> <string name="cling_dismiss" msgid="8962359497601507581">"ОК"</string> @@ -107,4 +112,14 @@ <string name="widget_button_text" msgid="2880537293434387943">"Виджеты"</string> <string name="wallpaper_button_text" msgid="8404103075899945851">"Обои"</string> <string name="settings_button_text" msgid="8119458837558863227">"Настройки"</string> + <string name="package_state_enqueued" msgid="6227252464303085641">"Ожидается"</string> + <string name="package_state_downloading" msgid="4088770468458724721">"Скачивается"</string> + <string name="package_state_installing" msgid="7588193972189849870">"Устанавливается"</string> + <string name="package_state_unknown" msgid="7592128424511031410">"Неизвестно"</string> + <string name="package_state_error" msgid="7672093962724223588">"Не восстановлен"</string> + <string name="abandoned_clean_all" msgid="5256770727689657618">"Удалить все"</string> + <string name="abandoned_clean_this" msgid="7610119707847920412">"Удалить"</string> + <string name="abandoned_search" msgid="891119232568284442">"Найти"</string> + <string name="abandoned_promises_title" msgid="7096178467971716750">"Приложение не установлено"</string> + <string name="abandoned_promise_explanation" msgid="3990027586878167529">"Приложение не установлено. Вы можете удалить значок или найти приложение и установить его вручную."</string> </resources> diff --git a/res/values-si-rLK/strings.xml b/res/values-si-rLK/strings.xml new file mode 100644 index 000000000..d334da92b --- /dev/null +++ b/res/values-si-rLK/strings.xml @@ -0,0 +1,122 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +* Copyright (C) 2008 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. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="application_name" msgid="5181331383435256801">"Launcher3"</string> + <string name="home" msgid="7658288663002113681">"මුල් පිටුව"</string> + <string name="uid_name" msgid="7820867637514617527">"Android මධ්ය යෙදුම්"</string> + <string name="folder_name" msgid="7371454440695724752"></string> + <string name="activity_not_found" msgid="8071924732094499514">"යෙදුම ස්ථාපනය කර නැත."</string> + <!-- no translation found for safemode_shortcut_error (9160126848219158407) --> + <skip /> + <string name="widgets_tab_label" msgid="2921133187116603919">"විජට්"</string> + <string name="widget_adder" msgid="3201040140710381657">"විජට්"</string> + <string name="toggle_weight_watcher" msgid="5645299835184636119">"Mem පෙන්වන්න"</string> + <string name="long_press_widget_to_add" msgid="7699152356777458215">"විජට් එක ස්පර්ශ කර අහුලා ගැනීමට අල්ලාගෙන සිටින්න."</string> + <string name="market" msgid="2619650989819296998">"සාප්පුයාම"</string> + <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string> + <string name="external_drop_widget_error" msgid="3165821058322217155">"මෙම මුල් පිටු තිරය වෙත අයිතමය ඇද හෙළිය නොහැකි විය."</string> + <string name="external_drop_widget_pick_title" msgid="3486317258037690630">"සැදීමට විජට් එක තෝරන්න"</string> + <string name="rename_folder_label" msgid="3727762225964550653">"ෆෝල්ඩරයේ නම"</string> + <string name="rename_folder_title" msgid="3771389277707820891">"ෆෝල්ඩරය නැවත නම් කරන්න"</string> + <string name="rename_action" msgid="5559600076028658757">"හරි"</string> + <string name="cancel_action" msgid="7009134900002915310">"අවලංගු කරන්න"</string> + <string name="menu_item_add_item" msgid="1264911265836810421">"මුල් පිටු තිරය වෙත එක් කරන්න"</string> + <string name="group_applications" msgid="3797214114206693605">"යෙදුම්"</string> + <string name="group_shortcuts" msgid="6012256992764410535">"කෙටිමං"</string> + <string name="group_widgets" msgid="1569030723286851002">"විජට්"</string> + <string name="completely_out_of_space" msgid="6106288382070760318">"මෙම මුල් පිටු තිර මත තවත් ඉඩ නැත."</string> + <string name="out_of_space" msgid="4691004494942118364">"මෙම මුල් පිටු තිරය මත තවත් අවසර නැත."</string> + <string name="hotseat_out_of_space" msgid="7448809638125333693">"ප්රියතම දෑ ඇති තැටියේ තවත් ඉඩ නොමැත"</string> + <string name="invalid_hotseat_item" msgid="5779907847267573691">"ප්රියතම දෑ ඇති තැටිය සඳහා මෙම විජටය ඉතා විශාලය"</string> + <string name="shortcut_installed" msgid="1701742129426969556">"\"<xliff:g id="NAME">%s</xliff:g>\" කෙටිමග සාදන ලදි."</string> + <string name="shortcut_uninstalled" msgid="8176767991305701821">"\"<xliff:g id="NAME">%s</xliff:g>\" කෙටිමග ඉවත් කෙරිණි."</string> + <string name="shortcut_duplicate" msgid="9167217446062498127">"\"<xliff:g id="NAME">%s</xliff:g>\" කෙටිමග දැනටමත් පවතී."</string> + <string name="title_select_shortcut" msgid="6680642571148153868">"කෙටිමග තේරීම"</string> + <string name="title_select_application" msgid="3280812711670683644">"යෙදුම තේරීම"</string> + <string name="all_apps_button_label" msgid="9110807029020582876">"යෙදුම්"</string> + <string name="all_apps_home_button_label" msgid="252062713717058851">"මුල් පිටුව"</string> + <string name="delete_zone_label_workspace" msgid="4009607676751398685">"ඉවත් කරන්න"</string> + <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"අස්ථාපනය කරන්න"</string> + <string name="delete_target_label" msgid="1822697352535677073">"ඉවත් කරන්න"</string> + <string name="delete_target_uninstall_label" msgid="5100785476250872595">"අස්ථාපනය කරන්න"</string> + <string name="info_target_label" msgid="8053346143994679532">"යෙදුම් තොරතුරු"</string> + <string name="accessibility_search_button" msgid="1628520399424565142">"සොයන්න"</string> + <string name="accessibility_voice_search_button" msgid="4637324840434406584">"හඬ සෙවීම"</string> + <string name="accessibility_all_apps_button" msgid="2603132375383800483">"යෙදුම්"</string> + <string name="accessibility_delete_button" msgid="6466114477993744621">"ඉවත් කරන්න"</string> + <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"යාවත්කාලිනය අස්ථාපනය කරන්න"</string> + <string name="cab_menu_delete_app" msgid="7435191475867183689">"යෙදුම අස්ථාපනය කරන්න"</string> + <string name="cab_menu_app_info" msgid="8593722221450362342">"යෙදුම් විස්තර"</string> + <string name="cab_app_selection_text" msgid="374688303047985416">"1 යෙදුමක් තෝරා ඇත"</string> + <string name="cab_widget_selection_text" msgid="1833458597831541241">"1 විජටයක් තෝරා ඇත"</string> + <string name="cab_folder_selection_text" msgid="7999992513806132118">"1 ෆෝල්ඩරයක් තෝරා ඇත"</string> + <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"1 කෙටිමඟක් තෝරා ඇත"</string> + <string name="permlab_install_shortcut" msgid="5632423390354674437">"කෙටිමං ස්ථාපනය කරන්න"</string> + <string name="permdesc_install_shortcut" msgid="923466509822011139">"පරිශීලක මැදිහත්වීමෙන් තොරව කෙටිමං එක් කිරීමට යෙදුමකට අවසර දෙයි."</string> + <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"කෙටිමං අස්ථාපනය කරන්න"</string> + <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"පරිශීලකයාගේ මැදිහත්වීමෙන් තොරව කෙටිමං ඉවත් කිරීමට යෙදුමකට අවසර දෙයි."</string> + <string name="permlab_read_settings" msgid="1941457408239617576">"මුල් පිටු සැකසීම් සහ කෙටිමං කියවන්න"</string> + <string name="permdesc_read_settings" msgid="5833423719057558387">"මුල් පිටුවේ ඇති සැකසීම් සහ කෙටිමං කියවීමට යෙදුමකට අවසර දෙයි."</string> + <string name="permlab_write_settings" msgid="3574213698004620587">"මුල් පිටු සැකසීම් සහ කෙටිමං ලියන්න"</string> + <string name="permdesc_write_settings" msgid="5440712911516509985">"මුල් පිටුවේ සැකසීම් සහ කෙටිමං ඉවත් කිරීමට යෙදුමට අවසර දෙයි."</string> + <string name="gadget_error_text" msgid="6081085226050792095">"ගැටලු පූරණ විජට් එක"</string> + <string name="uninstall_system_app_text" msgid="4172046090762920660">"මෙය පද්ධති යෙදුමක් වන අතර අස්ථාපනය කළ නොහැක."</string> + <string name="dream_name" msgid="1530253749244328964">"රොකට් ආරම්භකය"</string> + <string name="folder_hint_text" msgid="6617836969016293992">"නම් නොකළ ෆෝල්ඩරය"</string> + <string name="workspace_description_format" msgid="2950174241104043327">"මුල් පිටු තිරය %1$d"</string> + <string name="default_scroll_format" msgid="7475544710230993317">"%2$d හි %1$d පිටුව"</string> + <string name="workspace_scroll_format" msgid="8458889198184077399">"මුල් පිටු තිරය %2$d හි %1$d"</string> + <string name="apps_customize_apps_scroll_format" msgid="370005296147130238">"%2$d හි %1$d යෙදුම් පිටුව"</string> + <string name="apps_customize_widgets_scroll_format" msgid="3106209519974971521">"විජට් පිටුව %2$d හි %1$d"</string> + <string name="first_run_cling_title" msgid="2459738000155917941">"සාදරයෙන් පිළිගනිමු"</string> + <string name="first_run_cling_description" msgid="6447072552696253358">"ගෙදර ඉන්නවා වගේ ඉන්න."</string> + <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string> + <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string> + <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"යෙදුම් සහ ෆෝල්ඩර සඳහා තවත් තිර සාදන්න"</string> + <string name="migration_cling_title" msgid="9181776667882933767">"ඔබේ යෙදුම් නිරූපක පිටපත් කිරීම"</string> + <string name="migration_cling_description" msgid="2752413805582227644">"ඔබගේ පැරණි මුල් තිර වල නිරූපක සහ ෆෝල්ඩර ආයාත කරන්නද?"</string> + <string name="migration_cling_copy_apps" msgid="946331230090919440">"නිරූපක පිටපත් කරන්න"</string> + <string name="migration_cling_use_default" msgid="2626475813981258626">"අලුතින් පටන්ගන්න"</string> + <string name="workspace_cling_title" msgid="5626202359865825661">"ඔබගේ ඉඩ සංවිධානය කරගන්න"</string> + <string name="workspace_cling_move_item" msgid="528201129978005352">"බිතුපත, විජට් සහ සැකසීම් කළමනාකරණය කිරීමට පසුබිම ස්පර්ශ කර අල්ලාගෙන සිටින්න."</string> + <string name="folder_cling_title" msgid="3894908818693254164">"මෙන්න ෆෝල්ඩරයක්"</string> + <string name="folder_cling_create_folder" msgid="6158215559475836131">"මෙවැනි එකක් තැනීමට, යෙදුමක් තට්ටු කර අල්ලාගෙන සිටින්න, අනතුරුව එය තවත් එකක් උඩින් ගෙන යන්න."</string> + <string name="cling_dismiss" msgid="8962359497601507581">"හරි"</string> + <string name="folder_opened" msgid="94695026776264709">"ෆෝල්ඩරය විවෘත විය, <xliff:g id="WIDTH">%1$d</xliff:g> හි <xliff:g id="HEIGHT">%2$d</xliff:g>"</string> + <string name="folder_tap_to_close" msgid="1884479294466410023">"ෆෝල්ඩරය වැසීමට ස්පර්ශ කරන්න"</string> + <string name="folder_tap_to_rename" msgid="9191075570492871147">"නැවත නම් කිරීම සුරැකීමට ස්පර්ශ කරන්න"</string> + <string name="folder_closed" msgid="4100806530910930934">"ෆෝල්ඩරය වසා ඇත"</string> + <string name="folder_renamed" msgid="1794088362165669656">"<xliff:g id="NAME">%1$s</xliff:g> වෙත ෆෝල්ඩරය නැවත නම් කෙරිණි"</string> + <string name="folder_name_format" msgid="6629239338071103179">"ෆෝල්ඩරය: <xliff:g id="NAME">%1$s</xliff:g>"</string> + <string name="widget_button_text" msgid="2880537293434387943">"විජට්"</string> + <string name="wallpaper_button_text" msgid="8404103075899945851">"වෝල්පේපර"</string> + <string name="settings_button_text" msgid="8119458837558863227">"සැකසීම්"</string> + <string name="package_state_enqueued" msgid="6227252464303085641">"රැඳී සිටිමින්"</string> + <string name="package_state_downloading" msgid="4088770468458724721">"බාගනිමින්"</string> + <string name="package_state_installing" msgid="7588193972189849870">"ස්ථාපනය කරමින්"</string> + <string name="package_state_unknown" msgid="7592128424511031410">"නොදනී"</string> + <string name="package_state_error" msgid="7672093962724223588">"ප්රතිස්ථාපනය කළේ නැත"</string> + <string name="abandoned_clean_all" msgid="5256770727689657618">"සියල්ල ඉවත් කරන්න"</string> + <string name="abandoned_clean_this" msgid="7610119707847920412">"ඉවත් කරන්න"</string> + <string name="abandoned_search" msgid="891119232568284442">"සොයන්න"</string> + <string name="abandoned_promises_title" msgid="7096178467971716750">"මෙම යෙදුම ස්ථාපනය කර නොමැත"</string> + <string name="abandoned_promise_explanation" msgid="3990027586878167529">"මෙම නිරුපකයට යෙදුම ස්ථාපනය කර නොමැත. ඔබට එය ඉවත් කළ හැක, හෝ යෙදුම් සඳහා සොයන්න සහ අතින් ස්ථාපනය කරන්න."</string> +</resources> diff --git a/res/values-sk/strings.xml b/res/values-sk/strings.xml index acd8e051c..a00367949 100644 --- a/res/values-sk/strings.xml +++ b/res/values-sk/strings.xml @@ -24,6 +24,7 @@ <string name="uid_name" msgid="7820867637514617527">"Android Core Apps"</string> <string name="folder_name" msgid="7371454440695724752"></string> <string name="activity_not_found" msgid="8071924732094499514">"Aplikácia nie je nainštalovaná."</string> + <string name="safemode_shortcut_error" msgid="9160126848219158407">"Stiahnutá aplikácia je v núdzovom režime zakázaná"</string> <string name="widgets_tab_label" msgid="2921133187116603919">"Miniaplikácie"</string> <string name="widget_adder" msgid="3201040140710381657">"Miniaplikácie"</string> <string name="toggle_weight_watcher" msgid="5645299835184636119">"Zobraziť pamäť"</string> @@ -76,6 +77,7 @@ <string name="permlab_write_settings" msgid="3574213698004620587">"zápis nastavení a odkazov plochy"</string> <string name="permdesc_write_settings" msgid="5440712911516509985">"Povoľuje aplikácii zmeniť nastavenia a odkazy na ploche."</string> <string name="gadget_error_text" msgid="6081085226050792095">"Problém s načítaním miniaplikácií"</string> + <string name="gadget_setup_text" msgid="8274003207686040488">"Nastavenie"</string> <string name="uninstall_system_app_text" msgid="4172046090762920660">"Toto je systémová aplikácia a nedá sa odinštalovať."</string> <string name="dream_name" msgid="1530253749244328964">"Raketomet"</string> <string name="folder_hint_text" msgid="6617836969016293992">"Nepomenovaný priečinok"</string> @@ -95,6 +97,9 @@ <string name="migration_cling_use_default" msgid="2626475813981258626">"ZAČAŤ S PREDVOLENÝM ROZLOŽENÍM"</string> <string name="workspace_cling_title" msgid="5626202359865825661">"Usporiadajte svoj priestor"</string> <string name="workspace_cling_move_item" msgid="528201129978005352">"Ak chcete spravovať tapetu, miniaplikácie a nastavenia, dotknite sa pozadia a podržte."</string> + <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Pozadia, miniaplikácie a nastavenia"</string> + <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"Ak si chcete pozadie prispôsobiť, klepnite naň a podržte ho"</string> + <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"ROZUMIEM"</string> <string name="folder_cling_title" msgid="3894908818693254164">"Tu je priečinok"</string> <string name="folder_cling_create_folder" msgid="6158215559475836131">"Ak chcete vytvoriť takýto priečinok, dotknite sa príslušnej aplikácie a podržte ju. Potom ju presuňte na druhú aplikáciu."</string> <string name="cling_dismiss" msgid="8962359497601507581">"OK"</string> @@ -107,4 +112,14 @@ <string name="widget_button_text" msgid="2880537293434387943">"Miniaplikácie"</string> <string name="wallpaper_button_text" msgid="8404103075899945851">"Tapety"</string> <string name="settings_button_text" msgid="8119458837558863227">"Nastavenia"</string> + <string name="package_state_enqueued" msgid="6227252464303085641">"Čaká sa"</string> + <string name="package_state_downloading" msgid="4088770468458724721">"Sťahovanie"</string> + <string name="package_state_installing" msgid="7588193972189849870">"Inštalácia"</string> + <string name="package_state_unknown" msgid="7592128424511031410">"Neznáme"</string> + <string name="package_state_error" msgid="7672093962724223588">"Nebolo obnovené"</string> + <string name="abandoned_clean_all" msgid="5256770727689657618">"Odstrániť všetky"</string> + <string name="abandoned_clean_this" msgid="7610119707847920412">"Odstrániť"</string> + <string name="abandoned_search" msgid="891119232568284442">"Vyhľadať"</string> + <string name="abandoned_promises_title" msgid="7096178467971716750">"Táto aplikácia nie je nainštalovaná"</string> + <string name="abandoned_promise_explanation" msgid="3990027586878167529">"Aplikácia, ktorú zastupuje táto ikona, nie je nainštalovaná. Ikonu môžete odstrániť alebo vyhľadajte aplikáciu a ručne ju nainštalujte."</string> </resources> diff --git a/res/values-sl/strings.xml b/res/values-sl/strings.xml index afbd6202e..9c5bebd15 100644 --- a/res/values-sl/strings.xml +++ b/res/values-sl/strings.xml @@ -24,6 +24,7 @@ <string name="uid_name" msgid="7820867637514617527">"Osnovne aplikacije sistema Android"</string> <string name="folder_name" msgid="7371454440695724752"></string> <string name="activity_not_found" msgid="8071924732094499514">"Aplikacija ni nameščena."</string> + <string name="safemode_shortcut_error" msgid="9160126848219158407">"Prenesena aplikacija je onemogočena v Varnem načinu"</string> <string name="widgets_tab_label" msgid="2921133187116603919">"Pripomočki"</string> <string name="widget_adder" msgid="3201040140710381657">"Pripomočki"</string> <string name="toggle_weight_watcher" msgid="5645299835184636119">"Pokaži pomnilnik"</string> @@ -76,6 +77,7 @@ <string name="permlab_write_settings" msgid="3574213698004620587">"zapis nastavitev in bližnjic na začetnem zaslonu"</string> <string name="permdesc_write_settings" msgid="5440712911516509985">"Aplikaciji dovoli spreminjanje nastavitev in bližnjic na začetnem zaslonu."</string> <string name="gadget_error_text" msgid="6081085226050792095">"Težava pri nalaganju pripomočka"</string> + <string name="gadget_setup_text" msgid="8274003207686040488">"Nastavitev"</string> <string name="uninstall_system_app_text" msgid="4172046090762920660">"To je sistemska aplikacija in je ni mogoče odstraniti."</string> <string name="dream_name" msgid="1530253749244328964">"Raketno izstrelišče"</string> <string name="folder_hint_text" msgid="6617836969016293992">"Neimenovana mapa"</string> @@ -95,6 +97,9 @@ <string name="migration_cling_use_default" msgid="2626475813981258626">"SVEŽ ZAČETEK"</string> <string name="workspace_cling_title" msgid="5626202359865825661">"Organizirajte svoj prostor"</string> <string name="workspace_cling_move_item" msgid="528201129978005352">"Če želite upravljati ozadje, pripomočke in nastavitve, se dotaknite ozadja in ga pridržite."</string> + <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Ozadja, pripomočki in nastavitve"</string> + <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"Za prilagajanje se dotaknite ozadja in ga pridržite"</string> + <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"V REDU"</string> <string name="folder_cling_title" msgid="3894908818693254164">"To je mapa"</string> <string name="folder_cling_create_folder" msgid="6158215559475836131">"Če želite ustvariti mapo, podobno tej, se dotaknite aplikacije in jo pridržite, nato pa jo premaknite nad drugo."</string> <string name="cling_dismiss" msgid="8962359497601507581">"V redu"</string> @@ -107,4 +112,14 @@ <string name="widget_button_text" msgid="2880537293434387943">"Pripomočki"</string> <string name="wallpaper_button_text" msgid="8404103075899945851">"Ozadja"</string> <string name="settings_button_text" msgid="8119458837558863227">"Nastavitve"</string> + <string name="package_state_enqueued" msgid="6227252464303085641">"Čakanje"</string> + <string name="package_state_downloading" msgid="4088770468458724721">"Prenašanje"</string> + <string name="package_state_installing" msgid="7588193972189849870">"Nameščanje"</string> + <string name="package_state_unknown" msgid="7592128424511031410">"Neznano"</string> + <string name="package_state_error" msgid="7672093962724223588">"Ni obnovljen"</string> + <string name="abandoned_clean_all" msgid="5256770727689657618">"Odstrani vse"</string> + <string name="abandoned_clean_this" msgid="7610119707847920412">"Odstrani"</string> + <string name="abandoned_search" msgid="891119232568284442">"Iskanje"</string> + <string name="abandoned_promises_title" msgid="7096178467971716750">"Ta aplikacija ni nameščena."</string> + <string name="abandoned_promise_explanation" msgid="3990027586878167529">"Aplikacija za to ikono ni nameščena. Lahko jo odstranite ali poiščete aplikacijo in to namestite ročno."</string> </resources> diff --git a/res/values-sr/strings.xml b/res/values-sr/strings.xml index bf71b2821..421f8d3ac 100644 --- a/res/values-sr/strings.xml +++ b/res/values-sr/strings.xml @@ -24,6 +24,7 @@ <string name="uid_name" msgid="7820867637514617527">"Основне Android апликације"</string> <string name="folder_name" msgid="7371454440695724752"></string> <string name="activity_not_found" msgid="8071924732094499514">"Апликација није инсталирана."</string> + <string name="safemode_shortcut_error" msgid="9160126848219158407">"Преузета апликација је онемогућена у Безбедном режиму"</string> <string name="widgets_tab_label" msgid="2921133187116603919">"Виџети"</string> <string name="widget_adder" msgid="3201040140710381657">"Виџети"</string> <string name="toggle_weight_watcher" msgid="5645299835184636119">"Прикажи меморију"</string> @@ -76,6 +77,7 @@ <string name="permlab_write_settings" msgid="3574213698004620587">"уписивање подешавања и пречица на почетном екрану"</string> <string name="permdesc_write_settings" msgid="5440712911516509985">"Дозвољава апликацији да мења подешавања и пречице на почетном екрану."</string> <string name="gadget_error_text" msgid="6081085226050792095">"Проблем при учитавању виџета"</string> + <string name="gadget_setup_text" msgid="8274003207686040488">"Подешавање"</string> <string name="uninstall_system_app_text" msgid="4172046090762920660">"Ово је системска апликација и не може да се деинсталира."</string> <string name="dream_name" msgid="1530253749244328964">"Лансер ракета"</string> <string name="folder_hint_text" msgid="6617836969016293992">"Неименовани директоријум"</string> @@ -95,6 +97,9 @@ <string name="migration_cling_use_default" msgid="2626475813981258626">"ПОЧНИТЕ ИСПОЧЕТКА"</string> <string name="workspace_cling_title" msgid="5626202359865825661">"Организујте простор"</string> <string name="workspace_cling_move_item" msgid="528201129978005352">"Додирните позадину и задржите да бисте управљали позадином, виџетима и подешавањима."</string> + <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Позадине, виџети и подешавања"</string> + <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"Додирните и задржите позадину да бисте прилагодили"</string> + <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"ВАЖИ"</string> <string name="folder_cling_title" msgid="3894908818693254164">"Ево једног директоријума"</string> <string name="folder_cling_create_folder" msgid="6158215559475836131">"Да бисте направили директоријум попут овога, додирните и задржите апликацију, па је превуците преко друге."</string> <string name="cling_dismiss" msgid="8962359497601507581">"Потврди"</string> @@ -107,4 +112,14 @@ <string name="widget_button_text" msgid="2880537293434387943">"Виџети"</string> <string name="wallpaper_button_text" msgid="8404103075899945851">"Позадине"</string> <string name="settings_button_text" msgid="8119458837558863227">"Подешавања"</string> + <string name="package_state_enqueued" msgid="6227252464303085641">"Чека се"</string> + <string name="package_state_downloading" msgid="4088770468458724721">"Преузима се"</string> + <string name="package_state_installing" msgid="7588193972189849870">"Инсталира се"</string> + <string name="package_state_unknown" msgid="7592128424511031410">"Непознато"</string> + <string name="package_state_error" msgid="7672093962724223588">"Није враћено"</string> + <string name="abandoned_clean_all" msgid="5256770727689657618">"Уклони све"</string> + <string name="abandoned_clean_this" msgid="7610119707847920412">"Уклони"</string> + <string name="abandoned_search" msgid="891119232568284442">"Претражи"</string> + <string name="abandoned_promises_title" msgid="7096178467971716750">"Ова апликација није инсталирана"</string> + <string name="abandoned_promise_explanation" msgid="3990027586878167529">"Апликација за ову икону није инсталирана. Можете да је уклоните или да потражите апликацију и инсталирате је ручно."</string> </resources> diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml index 5825eecbd..e149c9efa 100644 --- a/res/values-sv/strings.xml +++ b/res/values-sv/strings.xml @@ -24,6 +24,7 @@ <string name="uid_name" msgid="7820867637514617527">"Android Core Apps"</string> <string name="folder_name" msgid="7371454440695724752"></string> <string name="activity_not_found" msgid="8071924732094499514">"Appen är inte installerad."</string> + <string name="safemode_shortcut_error" msgid="9160126848219158407">"Den hämtade appen inaktiverades i säkert läge"</string> <string name="widgets_tab_label" msgid="2921133187116603919">"Widgetar"</string> <string name="widget_adder" msgid="3201040140710381657">"Widgetar"</string> <string name="toggle_weight_watcher" msgid="5645299835184636119">"Visa Mem"</string> @@ -76,6 +77,7 @@ <string name="permlab_write_settings" msgid="3574213698004620587">"skriva inställningar och genvägar för startsidan"</string> <string name="permdesc_write_settings" msgid="5440712911516509985">"Tillåter att appen ändrar inställningar och genvägar på startsidan."</string> <string name="gadget_error_text" msgid="6081085226050792095">"Det gick inte att läsa in widgeten"</string> + <string name="gadget_setup_text" msgid="8274003207686040488">"Konfiguration"</string> <string name="uninstall_system_app_text" msgid="4172046090762920660">"Det här är en systemapp som inte kan avinstalleras."</string> <string name="dream_name" msgid="1530253749244328964">"Rocket Launcher"</string> <string name="folder_hint_text" msgid="6617836969016293992">"Namnlös mapp"</string> @@ -95,6 +97,9 @@ <string name="migration_cling_use_default" msgid="2626475813981258626">"BÖRJA OM"</string> <string name="workspace_cling_title" msgid="5626202359865825661">"Organisera ditt utrymme"</string> <string name="workspace_cling_move_item" msgid="528201129978005352">"Tryck länge på bakgrunden om du vill hantera bakgrundsbilder, widgetar och inställningar."</string> + <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Bakgrunder, widgetar och inställningar"</string> + <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"Tryck länge på bakgrunden om du vill anpassa den"</string> + <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"OK"</string> <string name="folder_cling_title" msgid="3894908818693254164">"Det här är en mapp"</string> <string name="folder_cling_create_folder" msgid="6158215559475836131">"Skapa en till mapp av det här slaget genom att trycka och hålla ned en app och sedan dra den ovanpå en annan."</string> <string name="cling_dismiss" msgid="8962359497601507581">"OK"</string> @@ -107,4 +112,14 @@ <string name="widget_button_text" msgid="2880537293434387943">"Widgetar"</string> <string name="wallpaper_button_text" msgid="8404103075899945851">"Bakgrunder"</string> <string name="settings_button_text" msgid="8119458837558863227">"Inställningar"</string> + <string name="package_state_enqueued" msgid="6227252464303085641">"Väntar"</string> + <string name="package_state_downloading" msgid="4088770468458724721">"Hämtas"</string> + <string name="package_state_installing" msgid="7588193972189849870">"Installerar"</string> + <string name="package_state_unknown" msgid="7592128424511031410">"Okänt"</string> + <string name="package_state_error" msgid="7672093962724223588">"Inte återställt"</string> + <string name="abandoned_clean_all" msgid="5256770727689657618">"Ta bort alla"</string> + <string name="abandoned_clean_this" msgid="7610119707847920412">"Ta bort"</string> + <string name="abandoned_search" msgid="891119232568284442">"Sök"</string> + <string name="abandoned_promises_title" msgid="7096178467971716750">"Appen är inte installerad"</string> + <string name="abandoned_promise_explanation" msgid="3990027586878167529">"Appen för den här ikonen har inte installerats. Du kan ta bort den eller söka efter appen och installera den manuellt."</string> </resources> diff --git a/res/values-sw/strings.xml b/res/values-sw/strings.xml index d2a282a47..07d091393 100644 --- a/res/values-sw/strings.xml +++ b/res/values-sw/strings.xml @@ -24,6 +24,7 @@ <string name="uid_name" msgid="7820867637514617527">"Programu Msingi za Android"</string> <string name="folder_name" msgid="7371454440695724752"></string> <string name="activity_not_found" msgid="8071924732094499514">"Programu haijasakinishwa."</string> + <string name="safemode_shortcut_error" msgid="9160126848219158407">"Programu iliyopakuliwa imezimwa katika Hali Salama"</string> <string name="widgets_tab_label" msgid="2921133187116603919">"Wijeti"</string> <string name="widget_adder" msgid="3201040140710381657">"Wijeti"</string> <string name="toggle_weight_watcher" msgid="5645299835184636119">"Onyesha Kumbukumbu"</string> @@ -76,6 +77,7 @@ <string name="permlab_write_settings" msgid="3574213698004620587">"andika mipangilio ya skrini ya Mwanzo na njia za mkato"</string> <string name="permdesc_write_settings" msgid="5440712911516509985">"Huruhusu programu kubadilisha mipangilio na njia za mkato katika skrini ya Mwanzo."</string> <string name="gadget_error_text" msgid="6081085226050792095">"Tatizo la kupakia wijeti"</string> + <string name="gadget_setup_text" msgid="8274003207686040488">"Sanidi"</string> <string name="uninstall_system_app_text" msgid="4172046090762920660">"Hii ni programu ya mfumo na haiwezi kuondolewa."</string> <string name="dream_name" msgid="1530253749244328964">"Kizinduzi cha Roketi"</string> <string name="folder_hint_text" msgid="6617836969016293992">"Folda isiyo na jina"</string> @@ -97,6 +99,9 @@ <string name="migration_cling_use_default" msgid="2626475813981258626">"ANZA UPYA"</string> <string name="workspace_cling_title" msgid="5626202359865825661">"Panga nafasi yako"</string> <string name="workspace_cling_move_item" msgid="528201129978005352">"Gusa na ushikilie mandharinyuma ili udhibiti mandhari, wijeti, na mipangilio."</string> + <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Mandhari, wijeti, na mipangilio"</string> + <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"Gusa na ushikilie mandhari ili uweke mapendeleo"</string> + <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"NIMEELEWA"</string> <string name="folder_cling_title" msgid="3894908818693254164">"Hii ni folda"</string> <string name="folder_cling_create_folder" msgid="6158215559475836131">"Ili kuunda kama hii, gusa na ushikilie programu, kisha ipitishe juu ya nyingine."</string> <string name="cling_dismiss" msgid="8962359497601507581">"SAWA"</string> @@ -109,4 +114,14 @@ <string name="widget_button_text" msgid="2880537293434387943">"Wijeti"</string> <string name="wallpaper_button_text" msgid="8404103075899945851">"Mandhari"</string> <string name="settings_button_text" msgid="8119458837558863227">"Mipangilio"</string> + <string name="package_state_enqueued" msgid="6227252464303085641">"Inasubiri"</string> + <string name="package_state_downloading" msgid="4088770468458724721">"Inapakua"</string> + <string name="package_state_installing" msgid="7588193972189849870">"Inasakinisha"</string> + <string name="package_state_unknown" msgid="7592128424511031410">"Yasiyojulikana"</string> + <string name="package_state_error" msgid="7672093962724223588">"Haijarejeshwa"</string> + <string name="abandoned_clean_all" msgid="5256770727689657618">"Ondoa Zote"</string> + <string name="abandoned_clean_this" msgid="7610119707847920412">"Ondoa"</string> + <string name="abandoned_search" msgid="891119232568284442">"Tafuta"</string> + <string name="abandoned_promises_title" msgid="7096178467971716750">"Programu hii haijasakinishwa"</string> + <string name="abandoned_promise_explanation" msgid="3990027586878167529">"Programu ya ikoni hii haijasakinishwa. Unaweza kuiondoa, au utafute programu na uisakinishe wewe mwenyewe."</string> </resources> diff --git a/res/values-sw600dp/config.xml b/res/values-sw600dp/config.xml index 2ec2f146c..15d5725d1 100644 --- a/res/values-sw600dp/config.xml +++ b/res/values-sw600dp/config.xml @@ -2,9 +2,6 @@ <bool name="is_tablet">true</bool> <bool name="allow_rotation">true</bool> - <!-- Whether or not to use custom clings if a custom workspace layout is passed in --> - <bool name="config_useCustomClings">true</bool> - <!-- DragController --> <integer name="config_flingToDeleteMinVelocity">-1000</integer> diff --git a/res/values-sw600dp/dimens.xml b/res/values-sw600dp/dimens.xml index 8d6c7f4e3..28679be2e 100644 --- a/res/values-sw600dp/dimens.xml +++ b/res/values-sw600dp/dimens.xml @@ -23,4 +23,13 @@ <dimen name="app_widget_preview_label_margin_top">8dp</dimen> <dimen name="app_widget_preview_label_margin_left">@dimen/app_widget_preview_padding_left</dimen> <dimen name="app_widget_preview_label_margin_right">@dimen/app_widget_preview_padding_right</dimen> + +<!-- Cling --> + <dimen name="cling_migration_logo_height">400dp</dimen> + <dimen name="cling_migration_logo_width">274dp</dimen> + <dimen name="cling_migration_bg_size">600dp</dimen> + <dimen name="cling_migration_bg_shift">-300dp</dimen> + <dimen name="cling_migration_content_margin">64dp</dimen> + <dimen name="cling_migration_content_width">280dp</dimen> + </resources> diff --git a/res/values-sw720dp-land/dimens.xml b/res/values-sw720dp-land/dimens.xml index 433a5d40d..ca13db05b 100644 --- a/res/values-sw720dp-land/dimens.xml +++ b/res/values-sw720dp-land/dimens.xml @@ -18,15 +18,8 @@ <!-- AppsCustomize --> <integer name="apps_customize_widget_cell_count_x">4</integer> <integer name="apps_customize_widget_cell_count_y">2</integer> - <integer name="apps_customize_cling_focused_x">4</integer> - <integer name="apps_customize_cling_focused_y">2</integer> <!-- the area at the edge of the screen that makes the workspace go left or right while you're dragging. --> <dimen name="scroll_zone">100dip</dimen> - -<!-- Cling --> - <!-- The offset for the text in the cling --> - <dimen name="cling_text_block_offset_x">140dp</dimen> - <dimen name="cling_text_block_offset_y">80dp</dimen> </resources> diff --git a/res/values-sw720dp-port/dimens.xml b/res/values-sw720dp-port/dimens.xml index 9fe312bfe..6f594d518 100644 --- a/res/values-sw720dp-port/dimens.xml +++ b/res/values-sw720dp-port/dimens.xml @@ -19,12 +19,4 @@ <!-- the area at the edge of the screen that makes the workspace go left or right while you're dragging. --> <dimen name="scroll_zone">40dp</dimen> - - <integer name="apps_customize_cling_focused_x">2</integer> - <integer name="apps_customize_cling_focused_y">2</integer> - -<!-- Cling --> - <!-- The offset for the text in the cling --> - <dimen name="cling_text_block_offset_x">80dp</dimen> - <dimen name="cling_text_block_offset_y">160dp</dimen> </resources> diff --git a/res/values-sw720dp/dimens.xml b/res/values-sw720dp/dimens.xml index 9ae155b3c..8be996474 100644 --- a/res/values-sw720dp/dimens.xml +++ b/res/values-sw720dp/dimens.xml @@ -25,4 +25,9 @@ the drag view should be offset from the position of the original view. --> <dimen name="dragViewOffsetX">0dp</dimen> <dimen name="dragViewOffsetY">0dp</dimen> + +<!-- Cling --> + <dimen name="cling_migration_content_margin">96dp</dimen> + <dimen name="cling_migration_content_width">320dp</dimen> + </resources> diff --git a/res/values-ta-rIN/strings.xml b/res/values-ta-rIN/strings.xml new file mode 100644 index 000000000..f3aef1cd7 --- /dev/null +++ b/res/values-ta-rIN/strings.xml @@ -0,0 +1,121 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +* Copyright (C) 2008 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. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="application_name" msgid="5181331383435256801">"லாஞ்சர்3"</string> + <string name="home" msgid="7658288663002113681">"முகப்பு"</string> + <string name="uid_name" msgid="7820867637514617527">"Android முக்கியப் பயன்பாடுகள்"</string> + <string name="folder_name" msgid="7371454440695724752"></string> + <string name="activity_not_found" msgid="8071924732094499514">"பயன்பாடு நிறுவப்படவில்லை."</string> + <string name="safemode_shortcut_error" msgid="9160126848219158407">"இறக்கிய பயன்பாடு பாதுகாப்பு முறையில் முடக்கப்பட்டது"</string> + <string name="widgets_tab_label" msgid="2921133187116603919">"விட்ஜெட்கள்"</string> + <string name="widget_adder" msgid="3201040140710381657">"விட்ஜெட்கள்"</string> + <string name="toggle_weight_watcher" msgid="5645299835184636119">"நினைவகத்தைக் காட்டு"</string> + <string name="long_press_widget_to_add" msgid="7699152356777458215">"விட்ஜெட்டைத் தேர்வுசெய்ய தொட்டுப் & பிடிக்கவும்."</string> + <string name="market" msgid="2619650989819296998">"ஷாப்"</string> + <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string> + <string name="external_drop_widget_error" msgid="3165821058322217155">"உருப்படியை இந்த முகப்புத் திரையில் விட முடியவில்லை."</string> + <string name="external_drop_widget_pick_title" msgid="3486317258037690630">"உருவாக்குவதற்கு விட்ஜெட்டைத் தேர்வுசெய்யவும்"</string> + <string name="rename_folder_label" msgid="3727762225964550653">"கோப்புறையின் பெயர்"</string> + <string name="rename_folder_title" msgid="3771389277707820891">"கோப்புறைக்கு மறுபெயரிடு"</string> + <string name="rename_action" msgid="5559600076028658757">"சரி"</string> + <string name="cancel_action" msgid="7009134900002915310">"ரத்துசெய்"</string> + <string name="menu_item_add_item" msgid="1264911265836810421">"முகப்புத் திரையில் சேர்"</string> + <string name="group_applications" msgid="3797214114206693605">"பயன்பாடுகள்"</string> + <string name="group_shortcuts" msgid="6012256992764410535">"குறுக்குவழிகள்"</string> + <string name="group_widgets" msgid="1569030723286851002">"விட்ஜெட்கள்"</string> + <string name="completely_out_of_space" msgid="6106288382070760318">"உங்கள் முகப்புத் திரைகளில் வேறு இடம் இல்லை."</string> + <string name="out_of_space" msgid="4691004494942118364">"முகப்புத் திரையில் இடமில்லை."</string> + <string name="hotseat_out_of_space" msgid="7448809638125333693">"பிடித்தவை ட்ரேயில் இடமில்லை"</string> + <string name="invalid_hotseat_item" msgid="5779907847267573691">"பிடித்தவை ட்ரேவிற்கு விட்ஜெட் மிகவும் பெரியது"</string> + <string name="shortcut_installed" msgid="1701742129426969556">"\"<xliff:g id="NAME">%s</xliff:g>\" குறுக்குவழி உருவாக்கப்பட்டது."</string> + <string name="shortcut_uninstalled" msgid="8176767991305701821">"\"<xliff:g id="NAME">%s</xliff:g>\" குறுக்குவழி அகற்றப்பட்டது."</string> + <string name="shortcut_duplicate" msgid="9167217446062498127">"\"<xliff:g id="NAME">%s</xliff:g>\" குறுக்குவழி ஏற்கனவே உள்ளது."</string> + <string name="title_select_shortcut" msgid="6680642571148153868">"குறுக்குவழியைத் தேர்வுசெய்யவும்"</string> + <string name="title_select_application" msgid="3280812711670683644">"பயன்பாட்டைத் தேர்வுசெய்யவும்"</string> + <string name="all_apps_button_label" msgid="9110807029020582876">"பயன்பாடுகள்"</string> + <string name="all_apps_home_button_label" msgid="252062713717058851">"முகப்பு"</string> + <string name="delete_zone_label_workspace" msgid="4009607676751398685">"அகற்று"</string> + <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"நிறுவல் நீக்கு"</string> + <string name="delete_target_label" msgid="1822697352535677073">"அகற்று"</string> + <string name="delete_target_uninstall_label" msgid="5100785476250872595">"நிறுவல் நீக்கு"</string> + <string name="info_target_label" msgid="8053346143994679532">"பயன்பாட்டுத் தகவல்"</string> + <string name="accessibility_search_button" msgid="1628520399424565142">"தேடு"</string> + <string name="accessibility_voice_search_button" msgid="4637324840434406584">"குரல் தேடல்"</string> + <string name="accessibility_all_apps_button" msgid="2603132375383800483">"பயன்பாடுகள்"</string> + <string name="accessibility_delete_button" msgid="6466114477993744621">"அகற்று"</string> + <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"புதுப்பிப்பை நிறுவல் நீக்கு"</string> + <string name="cab_menu_delete_app" msgid="7435191475867183689">"பயன்பாட்டை நிறுவல் நீக்கு"</string> + <string name="cab_menu_app_info" msgid="8593722221450362342">"பயன்பாட்டின் விவரங்கள்"</string> + <string name="cab_app_selection_text" msgid="374688303047985416">"1 பயன்பாடு தேர்ந்தெடுக்கப்பட்டது"</string> + <string name="cab_widget_selection_text" msgid="1833458597831541241">"1 விட்ஜெட் தேர்ந்தெடுக்கப்பட்டது"</string> + <string name="cab_folder_selection_text" msgid="7999992513806132118">"1 கோப்புறை தேர்ந்தெடுக்கப்பட்டது"</string> + <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"1 குறுக்குவழி தேர்ந்தெடுக்கப்பட்டது"</string> + <string name="permlab_install_shortcut" msgid="5632423390354674437">"குறுக்குவழிகளை நிறுவுதல்"</string> + <string name="permdesc_install_shortcut" msgid="923466509822011139">"பயனரின் அனுமதி இல்லாமல் குறுக்குவழிகளைச் சேர்க்கப் பயன்பாட்டை அனுமதிக்கிறது."</string> + <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"குறுக்குவழிகளை நிறுவல் நீக்குதல்"</string> + <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"பயனரின் அனுமதி இல்லாமல் குறுக்குவழிகளை அகற்ற பயன்பாட்டை அனுமதிக்கிறது."</string> + <string name="permlab_read_settings" msgid="1941457408239617576">"முகப்பின் அமைப்புகள் மற்றும் குறுக்குவழிகளைப் படித்தல்"</string> + <string name="permdesc_read_settings" msgid="5833423719057558387">"முகப்பில் உள்ள அமைப்புகள் மற்றும் குறுக்குவழிகளைப் படிக்க பயன்பாட்டை அனுமதிக்கிறது."</string> + <string name="permlab_write_settings" msgid="3574213698004620587">"முகப்பின் அமைப்புகள் மற்றும் குறுக்குவழிகளை எழுதுதல்"</string> + <string name="permdesc_write_settings" msgid="5440712911516509985">"முகப்பில் உள்ள அமைப்புகள் மற்றும் குறுக்குவழிகளை மாற்ற பயன்பாட்டை அனுமதிக்கிறது."</string> + <string name="gadget_error_text" msgid="6081085226050792095">"விட்ஜெட்டை ஏற்றுவதில் சிக்கல்"</string> + <string name="uninstall_system_app_text" msgid="4172046090762920660">"இது அமைப்பு பயன்பாடு என்பதால் நிறுவல் நீக்கம் செய்ய முடியாது."</string> + <string name="dream_name" msgid="1530253749244328964">"ராக்கெட் லாஞ்சர்"</string> + <string name="folder_hint_text" msgid="6617836969016293992">"பெயரிடப்படாத கோப்புறை"</string> + <string name="workspace_description_format" msgid="2950174241104043327">"முகப்புத் திரை %1$d"</string> + <string name="default_scroll_format" msgid="7475544710230993317">"பக்கம் %1$d / %2$d"</string> + <string name="workspace_scroll_format" msgid="8458889198184077399">"முகப்புத் திரை %1$d of %2$d"</string> + <string name="apps_customize_apps_scroll_format" msgid="370005296147130238">"பயன்பாடுகளின் பக்கம் %1$d / %2$d"</string> + <string name="apps_customize_widgets_scroll_format" msgid="3106209519974971521">"விட்ஜெட்களின் பக்கம் %1$d / %2$d"</string> + <string name="first_run_cling_title" msgid="2459738000155917941">"வரவேற்கிறோம்"</string> + <string name="first_run_cling_description" msgid="6447072552696253358">"உங்களுக்கேற்ற முறையில் உருவாக்கவும்."</string> + <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string> + <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string> + <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"பயன்பாடுகள் மற்றும் கோப்புறைகளுக்காகக் கூடுதல் திரைகளை உருவாக்கவும்"</string> + <string name="migration_cling_title" msgid="9181776667882933767">"பயன்பாட்டின் ஐகான்களை நகலெடுக்கவும்"</string> + <string name="migration_cling_description" msgid="2752413805582227644">"பழைய முகப்புத் திரைகளிலிருந்து ஐகான்களையும் கோப்புறைகளையும் இறக்குமதி செய்யவா?"</string> + <string name="migration_cling_copy_apps" msgid="946331230090919440">"ஐகான்களை நகலெடு"</string> + <string name="migration_cling_use_default" msgid="2626475813981258626">"புதிதாகத் தொடங்கு"</string> + <string name="workspace_cling_title" msgid="5626202359865825661">"இடத்தை ஒழுங்கமைக்கவும்"</string> + <string name="workspace_cling_move_item" msgid="528201129978005352">"வால்பேப்பர், விட்ஜெட்கள் மற்றும் அமைப்புகளை நிர்வகிப்பதற்கு பின்புலத்தைத் தொட்டுப் & பிடிக்கவும்."</string> + <string name="folder_cling_title" msgid="3894908818693254164">"இதோ கோப்புறை"</string> + <string name="folder_cling_create_folder" msgid="6158215559475836131">"இதுபோன்ற ஒன்றை உருவாக்கப் பயன்பாட்டைத் தொட்டுப் & பிடிக்கவும், பிறகு அதை வேறொன்றிற்கு நகர்த்தவும்."</string> + <string name="cling_dismiss" msgid="8962359497601507581">"சரி"</string> + <string name="folder_opened" msgid="94695026776264709">"திறக்கப்பட்டக் கோப்புறை, <xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g>"</string> + <string name="folder_tap_to_close" msgid="1884479294466410023">"கோப்புறையை மூட, தொடவும்"</string> + <string name="folder_tap_to_rename" msgid="9191075570492871147">"மறுபெயரிட்டதைச் சேமிக்க, தொடவும்"</string> + <string name="folder_closed" msgid="4100806530910930934">"கோப்புறை மூடப்பட்டது"</string> + <string name="folder_renamed" msgid="1794088362165669656">"கோப்புறை <xliff:g id="NAME">%1$s</xliff:g> என மறுபெயரிடப்பட்டது"</string> + <string name="folder_name_format" msgid="6629239338071103179">"கோப்புறை: <xliff:g id="NAME">%1$s</xliff:g>"</string> + <string name="widget_button_text" msgid="2880537293434387943">"விட்ஜெட்கள்"</string> + <string name="wallpaper_button_text" msgid="8404103075899945851">"வால்பேப்பர்கள்"</string> + <string name="settings_button_text" msgid="8119458837558863227">"அமைப்புகள்"</string> + <string name="package_state_enqueued" msgid="6227252464303085641">"காத்திருக்கிறது"</string> + <string name="package_state_downloading" msgid="4088770468458724721">"பதிவிறக்குகிறது"</string> + <string name="package_state_installing" msgid="7588193972189849870">"நிறுவுகிறது"</string> + <string name="package_state_unknown" msgid="7592128424511031410">"தெரியாதது"</string> + <string name="package_state_error" msgid="7672093962724223588">"மீட்டெடுக்க முடியாது"</string> + <string name="abandoned_clean_all" msgid="5256770727689657618">"அனைத்தையும் அகற்று"</string> + <string name="abandoned_clean_this" msgid="7610119707847920412">"அகற்று"</string> + <string name="abandoned_search" msgid="891119232568284442">"தேடு"</string> + <string name="abandoned_promises_title" msgid="7096178467971716750">"பயன்பாடு நிறுவப்படவில்லை"</string> + <string name="abandoned_promise_explanation" msgid="3990027586878167529">"ஐகானுக்கான பயன்பாடு நிறுவப்படவில்லை. இதை அகற்றலாம் அல்லது பயன்பாட்டைத் தேடி கைமுறையாக நிறுவலாம்."</string> +</resources> diff --git a/res/values-te-rIN/strings.xml b/res/values-te-rIN/strings.xml new file mode 100644 index 000000000..b48d6b80d --- /dev/null +++ b/res/values-te-rIN/strings.xml @@ -0,0 +1,121 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +* Copyright (C) 2008 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. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="application_name" msgid="5181331383435256801">"లాంచర్3"</string> + <string name="home" msgid="7658288663002113681">"హోమ్"</string> + <string name="uid_name" msgid="7820867637514617527">"Android ప్రధాన అనువర్తనాలు"</string> + <string name="folder_name" msgid="7371454440695724752"></string> + <string name="activity_not_found" msgid="8071924732094499514">"అనువర్తనం ఇన్స్టాల్ చేయబడలేదు."</string> + <string name="safemode_shortcut_error" msgid="9160126848219158407">"సురక్షిత మోడ్లో డౌన్లోడ్ చేసిన అనువర్తనం నిలిపివేయబడింది"</string> + <string name="widgets_tab_label" msgid="2921133187116603919">"విడ్జెట్లు"</string> + <string name="widget_adder" msgid="3201040140710381657">"విడ్జెట్లు"</string> + <string name="toggle_weight_watcher" msgid="5645299835184636119">"మెమరీ చూపు"</string> + <string name="long_press_widget_to_add" msgid="7699152356777458215">"విడ్జెట్ను ఎంచుకోవడానికి తాకి & నొక్కి పెట్టండి."</string> + <string name="market" msgid="2619650989819296998">"షాపింగ్ చేయి"</string> + <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string> + <string name="external_drop_widget_error" msgid="3165821058322217155">"ఈ హోమ్ స్క్రీన్లో అంశాన్ని వదలడం సాధ్యపడలేదు."</string> + <string name="external_drop_widget_pick_title" msgid="3486317258037690630">"సృష్టించాల్సిన విడ్జెట్ ఎంచుకోండి"</string> + <string name="rename_folder_label" msgid="3727762225964550653">"ఫోల్డర్ పేరు"</string> + <string name="rename_folder_title" msgid="3771389277707820891">"ఫోల్డర్ పేరు మార్చండి"</string> + <string name="rename_action" msgid="5559600076028658757">"సరే"</string> + <string name="cancel_action" msgid="7009134900002915310">"రద్దు చేయి"</string> + <string name="menu_item_add_item" msgid="1264911265836810421">"హోమ్ స్క్రీన్కు జోడించు"</string> + <string name="group_applications" msgid="3797214114206693605">"అనువర్తనాలు"</string> + <string name="group_shortcuts" msgid="6012256992764410535">"సత్వరమార్గాలు"</string> + <string name="group_widgets" msgid="1569030723286851002">"విడ్జెట్లు"</string> + <string name="completely_out_of_space" msgid="6106288382070760318">"మీ హోమ్ స్క్రీన్ల్లో ఖాళీ లేదు."</string> + <string name="out_of_space" msgid="4691004494942118364">"ఈ హోమ్ స్క్రీన్లో ఖాళీ లేదు."</string> + <string name="hotseat_out_of_space" msgid="7448809638125333693">"ఇష్టమైనవి ట్రేలో ఖాళీ లేదు"</string> + <string name="invalid_hotseat_item" msgid="5779907847267573691">"ఇష్టమైనవి ట్రే కోసం ఈ విడ్జెట్ చాలా పెద్దదిగా ఉంది"</string> + <string name="shortcut_installed" msgid="1701742129426969556">"సత్వరమార్గం \"<xliff:g id="NAME">%s</xliff:g>\" సృష్టించబడింది."</string> + <string name="shortcut_uninstalled" msgid="8176767991305701821">"సత్వరమార్గం \"<xliff:g id="NAME">%s</xliff:g>\" తీసివేయబడింది."</string> + <string name="shortcut_duplicate" msgid="9167217446062498127">"సత్వరమార్గం \"<xliff:g id="NAME">%s</xliff:g>\" ఇప్పటికే ఉంది."</string> + <string name="title_select_shortcut" msgid="6680642571148153868">"సత్వరమార్గాన్ని ఎంచుకోండి"</string> + <string name="title_select_application" msgid="3280812711670683644">"అనువర్తనాన్ని ఎంచుకోండి"</string> + <string name="all_apps_button_label" msgid="9110807029020582876">"అనువర్తనాలు"</string> + <string name="all_apps_home_button_label" msgid="252062713717058851">"హోమ్"</string> + <string name="delete_zone_label_workspace" msgid="4009607676751398685">"తీసివేయి"</string> + <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"అన్ఇన్స్టాల్ చేయి"</string> + <string name="delete_target_label" msgid="1822697352535677073">"తీసివేయి"</string> + <string name="delete_target_uninstall_label" msgid="5100785476250872595">"అన్ఇన్స్టాల్ చేయి"</string> + <string name="info_target_label" msgid="8053346143994679532">"అనువర్తన సమాచారం"</string> + <string name="accessibility_search_button" msgid="1628520399424565142">"శోధించు"</string> + <string name="accessibility_voice_search_button" msgid="4637324840434406584">"వాయిస్ శోధన"</string> + <string name="accessibility_all_apps_button" msgid="2603132375383800483">"అనువర్తనాలు"</string> + <string name="accessibility_delete_button" msgid="6466114477993744621">"తీసివేయి"</string> + <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"నవీకరణను అన్ఇన్స్టాల్ చేయి"</string> + <string name="cab_menu_delete_app" msgid="7435191475867183689">"అనువర్తనాన్ని అన్ఇన్స్టాల్ చేయి"</string> + <string name="cab_menu_app_info" msgid="8593722221450362342">"అనువర్తన వివరాలు"</string> + <string name="cab_app_selection_text" msgid="374688303047985416">"1 అనువర్తనం ఎంచుకోబడింది"</string> + <string name="cab_widget_selection_text" msgid="1833458597831541241">"1 విడ్జెట్ ఎంచుకోబడింది"</string> + <string name="cab_folder_selection_text" msgid="7999992513806132118">"1 ఫోల్డర్ ఎంచుకోబడింది"</string> + <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"1 సత్వరమార్గం ఎంచుకోబడింది"</string> + <string name="permlab_install_shortcut" msgid="5632423390354674437">"సత్వరమార్గాలను ఇన్స్టాల్ చేయడం"</string> + <string name="permdesc_install_shortcut" msgid="923466509822011139">"వినియోగదారు ప్రమేయం లేకుండా సత్వరమార్గాలను జోడించడానికి అనువర్తనాన్ని అనుమతిస్తుంది."</string> + <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"సత్వరమార్గాలను అన్ఇన్స్టాల్ చేయడం"</string> + <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"వినియోగదారు ప్రమేయం లేకుండా సత్వరమార్గాలను తీసివేయడానికి అనువర్తనాన్ని అనుమతిస్తుంది."</string> + <string name="permlab_read_settings" msgid="1941457408239617576">"హోమ్ సెట్టింగ్లు మరియు సత్వరమార్గాలను చదవడం"</string> + <string name="permdesc_read_settings" msgid="5833423719057558387">"హోమ్లో సెట్టింగ్లు మరియు సత్వరమార్గాలను చదవడానికి అనువర్తనాన్ని అనుమతిస్తుంది."</string> + <string name="permlab_write_settings" msgid="3574213698004620587">"హోమ్ సెట్టింగ్లు మరియు సత్వరమార్గాలను వ్రాయడం"</string> + <string name="permdesc_write_settings" msgid="5440712911516509985">"హోమ్లో సెట్టింగ్లు మరియు సత్వరమార్గాలను మార్చడానికి అనువర్తనాన్ని అనుమతిస్తుంది."</string> + <string name="gadget_error_text" msgid="6081085226050792095">"విడ్జెట్ను లోడ్ చేయడంలో సమస్య"</string> + <string name="uninstall_system_app_text" msgid="4172046090762920660">"ఇది సిస్టమ్ అనువర్తనం మరియు దీన్ని అన్ఇన్స్టాల్ చేయడం సాధ్యపడదు."</string> + <string name="dream_name" msgid="1530253749244328964">"రాకెట్ లాంచర్"</string> + <string name="folder_hint_text" msgid="6617836969016293992">"పేరు లేని ఫోల్డర్"</string> + <string name="workspace_description_format" msgid="2950174241104043327">"హోమ్ స్క్రీన్ %1$d"</string> + <string name="default_scroll_format" msgid="7475544710230993317">"%2$dలో %1$dవ పేజీ"</string> + <string name="workspace_scroll_format" msgid="8458889198184077399">"%2$dలో %1$dవ హోమ్ స్క్రీన్"</string> + <string name="apps_customize_apps_scroll_format" msgid="370005296147130238">"%2$dలో %1$dవ అనువర్తనాల పేజీ"</string> + <string name="apps_customize_widgets_scroll_format" msgid="3106209519974971521">"%2$dలో %1$dవ విడ్జెట్ల పేజీ"</string> + <string name="first_run_cling_title" msgid="2459738000155917941">"స్వాగతం"</string> + <string name="first_run_cling_description" msgid="6447072552696253358">"మీ స్వంత స్థలంగా భావించండి."</string> + <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string> + <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string> + <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"అనువర్తనాలు మరియు ఫోల్డర్ల కోసం మరిన్ని స్క్రీన్లు సృష్టి."</string> + <string name="migration_cling_title" msgid="9181776667882933767">"మీ అనువర్తన చిహ్నాలను కాపీ చేయండి"</string> + <string name="migration_cling_description" msgid="2752413805582227644">"మీ పాత హోమ్ స్క్రీన్ల నుండి చిహ్నాలు మరియు ఫోల్డర్లను దిగుమతి చేయాలా?"</string> + <string name="migration_cling_copy_apps" msgid="946331230090919440">"చిహ్నాలను కాపీ చేయి"</string> + <string name="migration_cling_use_default" msgid="2626475813981258626">"తాజాగా ప్రారంభించు"</string> + <string name="workspace_cling_title" msgid="5626202359865825661">"మీ స్థలాన్ని నిర్వహించండి"</string> + <string name="workspace_cling_move_item" msgid="528201129978005352">"వాల్., విడ్జె., సెట్టి. నిర్వ. నేపథ్యం తాకి & నొక్కి పెట్టండి."</string> + <string name="folder_cling_title" msgid="3894908818693254164">"ఇక్కడ ఫోల్డర్ ఉంది"</string> + <string name="folder_cling_create_folder" msgid="6158215559475836131">"ఇలాంటిది సృష్టించడానికి అనువర్తనాన్ని తాకి & నొక్కి పెట్టండి, ఆపై మరోదాని పైన ఉంచండి."</string> + <string name="cling_dismiss" msgid="8962359497601507581">"సరే"</string> + <string name="folder_opened" msgid="94695026776264709">"ఫోల్డర్ తెరవబడింది, <xliff:g id="WIDTH">%1$d</xliff:g> X <xliff:g id="HEIGHT">%2$d</xliff:g>"</string> + <string name="folder_tap_to_close" msgid="1884479294466410023">"ఫోల్డర్ను మూసివేయడానికి తాకండి"</string> + <string name="folder_tap_to_rename" msgid="9191075570492871147">"పేరు మార్పును సేవ్ చేయడానికి తాకండి"</string> + <string name="folder_closed" msgid="4100806530910930934">"ఫోల్డర్ మూసివేయబడింది"</string> + <string name="folder_renamed" msgid="1794088362165669656">"ఫోల్డర్ పేరు <xliff:g id="NAME">%1$s</xliff:g>గా మార్చబడింది"</string> + <string name="folder_name_format" msgid="6629239338071103179">"ఫోల్డర్: <xliff:g id="NAME">%1$s</xliff:g>"</string> + <string name="widget_button_text" msgid="2880537293434387943">"విడ్జెట్లు"</string> + <string name="wallpaper_button_text" msgid="8404103075899945851">"వాల్పేపర్లు"</string> + <string name="settings_button_text" msgid="8119458837558863227">"సెట్టింగ్లు"</string> + <string name="package_state_enqueued" msgid="6227252464303085641">"వేచి ఉంది"</string> + <string name="package_state_downloading" msgid="4088770468458724721">"డౌన్లోడ్ చేస్తోంది"</string> + <string name="package_state_installing" msgid="7588193972189849870">"ఇన్స్టాల్ చేస్తోంది"</string> + <string name="package_state_unknown" msgid="7592128424511031410">"తెలియదు"</string> + <string name="package_state_error" msgid="7672093962724223588">"పునరుద్ధరించబడలేదు"</string> + <string name="abandoned_clean_all" msgid="5256770727689657618">"అన్నీ తీసివేయి"</string> + <string name="abandoned_clean_this" msgid="7610119707847920412">"తీసివేయి"</string> + <string name="abandoned_search" msgid="891119232568284442">"శోధించు"</string> + <string name="abandoned_promises_title" msgid="7096178467971716750">"ఈ అనువర్తనం ఇన్స్టాల్ చేయబడలేదు"</string> + <string name="abandoned_promise_explanation" msgid="3990027586878167529">"ఈ చిహ్నం యొక్క అనువర్తనం ఇన్స్టాల్ చేయబడలేదు. మీరు దీన్ని తీసివేయవచ్చు లేదా ఆ అనువర్తనం కోసం శోధించి దాన్ని మాన్యువల్గా ఇన్స్టాల్ చేయవచ్చు."</string> +</resources> diff --git a/res/values-th/strings.xml b/res/values-th/strings.xml index beaa0ae81..beed89844 100644 --- a/res/values-th/strings.xml +++ b/res/values-th/strings.xml @@ -24,6 +24,7 @@ <string name="uid_name" msgid="7820867637514617527">"แอปหลักของ Android"</string> <string name="folder_name" msgid="7371454440695724752"></string> <string name="activity_not_found" msgid="8071924732094499514">"ไม่ได้ติดตั้งแอป"</string> + <string name="safemode_shortcut_error" msgid="9160126848219158407">"แอปที่ดาวน์โหลดถูกปิดในโหมดปลอดภัย"</string> <string name="widgets_tab_label" msgid="2921133187116603919">"วิดเจ็ต"</string> <string name="widget_adder" msgid="3201040140710381657">"วิดเจ็ต"</string> <string name="toggle_weight_watcher" msgid="5645299835184636119">"แสดง Mem"</string> @@ -51,15 +52,15 @@ <string name="title_select_application" msgid="3280812711670683644">"เลือกแอป"</string> <string name="all_apps_button_label" msgid="9110807029020582876">"แอป"</string> <string name="all_apps_home_button_label" msgid="252062713717058851">"หน้าแรก"</string> - <string name="delete_zone_label_workspace" msgid="4009607676751398685">"นำออก"</string> + <string name="delete_zone_label_workspace" msgid="4009607676751398685">"ลบ"</string> <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"ถอนการติดตั้ง"</string> - <string name="delete_target_label" msgid="1822697352535677073">"นำออก"</string> + <string name="delete_target_label" msgid="1822697352535677073">"ลบ"</string> <string name="delete_target_uninstall_label" msgid="5100785476250872595">"ถอนการติดตั้ง"</string> <string name="info_target_label" msgid="8053346143994679532">"ข้อมูลแอป"</string> <string name="accessibility_search_button" msgid="1628520399424565142">"ค้นหา"</string> <string name="accessibility_voice_search_button" msgid="4637324840434406584">"ค้นหาด้วยเสียง"</string> <string name="accessibility_all_apps_button" msgid="2603132375383800483">"แอป"</string> - <string name="accessibility_delete_button" msgid="6466114477993744621">"นำออก"</string> + <string name="accessibility_delete_button" msgid="6466114477993744621">"ลบ"</string> <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"ถอนการติดตั้งการอัปเดต"</string> <string name="cab_menu_delete_app" msgid="7435191475867183689">"ถอนการติดตั้งแอป"</string> <string name="cab_menu_app_info" msgid="8593722221450362342">"รายละเอียดแอป"</string> @@ -76,6 +77,7 @@ <string name="permlab_write_settings" msgid="3574213698004620587">"เขียนการตั้งค่าและทางลัดหน้าแรกแล้ว"</string> <string name="permdesc_write_settings" msgid="5440712911516509985">"อนุญาตให้แอปเปลี่ยนการตั้งค่าและทางลัดในหน้าแรก"</string> <string name="gadget_error_text" msgid="6081085226050792095">"มีปัญหาขณะโหลดวิดเจ็ต"</string> + <string name="gadget_setup_text" msgid="8274003207686040488">"ตั้งค่า"</string> <string name="uninstall_system_app_text" msgid="4172046090762920660">"นี่เป็นแอประบบและไม่สามารถถอนการติดตั้งได้"</string> <string name="dream_name" msgid="1530253749244328964">"Rocket Launcher"</string> <string name="folder_hint_text" msgid="6617836969016293992">"โฟลเดอร์ที่ไม่มีชื่อ"</string> @@ -95,6 +97,9 @@ <string name="migration_cling_use_default" msgid="2626475813981258626">"เริ่มต้นใหม่"</string> <string name="workspace_cling_title" msgid="5626202359865825661">"จัดระเบียบพื้นที่ของคุณ"</string> <string name="workspace_cling_move_item" msgid="528201129978005352">"แตะพื้นหลังค้างไว้เพื่อจัดการวอลเปเปอร์ วิดเจ็ต และการตั้งค่า"</string> + <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"วอลเปเปอร์ วิดเจ็ต และการตั้งค่า"</string> + <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"แตะพื้นหลังค้างไว้เพื่อกำหนดค่า"</string> + <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"รับทราบ"</string> <string name="folder_cling_title" msgid="3894908818693254164">"นี่คือโฟลเดอร์"</string> <string name="folder_cling_create_folder" msgid="6158215559475836131">"หากต้องการสร้างโฟลเดอร์ลักษณะนี้ แตะแอปค้างไว้ แล้วย้ายไปทับอีกแอปหนึ่ง"</string> <string name="cling_dismiss" msgid="8962359497601507581">"ตกลง"</string> @@ -107,4 +112,14 @@ <string name="widget_button_text" msgid="2880537293434387943">"วิดเจ็ต"</string> <string name="wallpaper_button_text" msgid="8404103075899945851">"วอลเปเปอร์"</string> <string name="settings_button_text" msgid="8119458837558863227">"การตั้งค่า"</string> + <string name="package_state_enqueued" msgid="6227252464303085641">"กำลังรอ"</string> + <string name="package_state_downloading" msgid="4088770468458724721">"กำลังดาวน์โหลด"</string> + <string name="package_state_installing" msgid="7588193972189849870">"กำลังติดตั้ง"</string> + <string name="package_state_unknown" msgid="7592128424511031410">"ไม่รู้จัก"</string> + <string name="package_state_error" msgid="7672093962724223588">"ไม่ได้คืนค่า"</string> + <string name="abandoned_clean_all" msgid="5256770727689657618">"ลบทั้งหมด"</string> + <string name="abandoned_clean_this" msgid="7610119707847920412">"ลบ"</string> + <string name="abandoned_search" msgid="891119232568284442">"ค้นหา"</string> + <string name="abandoned_promises_title" msgid="7096178467971716750">"ไม่ได้ติดตั้งแอปนี้"</string> + <string name="abandoned_promise_explanation" msgid="3990027586878167529">"ยังไม่ได้ติดตั้งแอปสำหรับไอคอนนี้ คุณสามารถนำไอคอนออก หรือค้นหาแอปดังกล่าวแล้วติดตั้งด้วยตนเอง"</string> </resources> diff --git a/res/values-tl/strings.xml b/res/values-tl/strings.xml index 5be9d85a8..7c6acd2ab 100644 --- a/res/values-tl/strings.xml +++ b/res/values-tl/strings.xml @@ -24,6 +24,7 @@ <string name="uid_name" msgid="7820867637514617527">"Android Core Apps"</string> <string name="folder_name" msgid="7371454440695724752"></string> <string name="activity_not_found" msgid="8071924732094499514">"Hindi naka-install ang app."</string> + <string name="safemode_shortcut_error" msgid="9160126848219158407">"Naka-disable ang na-download na app sa Safe mode"</string> <string name="widgets_tab_label" msgid="2921133187116603919">"Mga Widget"</string> <string name="widget_adder" msgid="3201040140710381657">"Mga Widget"</string> <string name="toggle_weight_watcher" msgid="5645299835184636119">"Ipakita ang Mem"</string> @@ -76,6 +77,7 @@ <string name="permlab_write_settings" msgid="3574213698004620587">"magsulat ng mga setting at shortcut ng Home"</string> <string name="permdesc_write_settings" msgid="5440712911516509985">"Pinapayagan ang app na baguhin ang mga setting at shortcut sa Home."</string> <string name="gadget_error_text" msgid="6081085226050792095">"Problema sa pag-load ng widget"</string> + <string name="gadget_setup_text" msgid="8274003207686040488">"I-setup"</string> <string name="uninstall_system_app_text" msgid="4172046090762920660">"Isa itong app ng system at hindi maaaring i-uninstall."</string> <string name="dream_name" msgid="1530253749244328964">"Rocket Launcher"</string> <string name="folder_hint_text" msgid="6617836969016293992">"Walang Pangalang Folder"</string> @@ -95,6 +97,9 @@ <string name="migration_cling_use_default" msgid="2626475813981258626">"MAGSIMULA NANG BAGO"</string> <string name="workspace_cling_title" msgid="5626202359865825661">"Ayusin ang iyong espasyo"</string> <string name="workspace_cling_move_item" msgid="528201129978005352">"Pindutin nang matagal ang background upang pamahalaan ang wallpaper, mga widget at setting"</string> + <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Mga wallpaper, widget at setting"</string> + <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"Pindutin nang matagal ang background upang i-customize"</string> + <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"NAKUHA KO"</string> <string name="folder_cling_title" msgid="3894908818693254164">"Narito ang isang folder"</string> <string name="folder_cling_create_folder" msgid="6158215559475836131">"Upang gumawa ng katulad nito, pindutin nang matagal ang isang app, pagkatapos ay ilipat ito sa isa pang folder."</string> <string name="cling_dismiss" msgid="8962359497601507581">"OK"</string> @@ -107,4 +112,14 @@ <string name="widget_button_text" msgid="2880537293434387943">"Mga Widget"</string> <string name="wallpaper_button_text" msgid="8404103075899945851">"Mga Wallpaper"</string> <string name="settings_button_text" msgid="8119458837558863227">"Mga Setting"</string> + <string name="package_state_enqueued" msgid="6227252464303085641">"Naghihintay"</string> + <string name="package_state_downloading" msgid="4088770468458724721">"Nagda-download"</string> + <string name="package_state_installing" msgid="7588193972189849870">"Nag-i-install"</string> + <string name="package_state_unknown" msgid="7592128424511031410">"Hindi kilala"</string> + <string name="package_state_error" msgid="7672093962724223588">"Hindi naibalik"</string> + <string name="abandoned_clean_all" msgid="5256770727689657618">"Alisin Lahat"</string> + <string name="abandoned_clean_this" msgid="7610119707847920412">"Alisin"</string> + <string name="abandoned_search" msgid="891119232568284442">"Maghanap"</string> + <string name="abandoned_promises_title" msgid="7096178467971716750">"Hindi naka-install ang app na ito"</string> + <string name="abandoned_promise_explanation" msgid="3990027586878167529">"Hindi naka-install ang app para sa icon na ito. Maaari mo itong alisin, o maaari mong hanapin ang app at i-install ito nang manu-mano."</string> </resources> diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml index 01f79a2e5..6c0bb69a7 100644 --- a/res/values-tr/strings.xml +++ b/res/values-tr/strings.xml @@ -24,11 +24,12 @@ <string name="uid_name" msgid="7820867637514617527">"Android Çekirdek Uygulamaları"</string> <string name="folder_name" msgid="7371454440695724752"></string> <string name="activity_not_found" msgid="8071924732094499514">"Uygulama yüklü değil."</string> + <string name="safemode_shortcut_error" msgid="9160126848219158407">"İndirilen uygulama Güvenli modda devre dışı bırakıldı"</string> <string name="widgets_tab_label" msgid="2921133187116603919">"Widget\'lar"</string> <string name="widget_adder" msgid="3201040140710381657">"Widget\'lar"</string> <string name="toggle_weight_watcher" msgid="5645299835184636119">"Belleği Göster"</string> <string name="long_press_widget_to_add" msgid="7699152356777458215">"Widget seçmek için dokunun ve basılı tutun."</string> - <string name="market" msgid="2619650989819296998">"Alışveriş yap"</string> + <string name="market" msgid="2619650989819296998">"Mağaza"</string> <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string> <string name="external_drop_widget_error" msgid="3165821058322217155">"Öğe bu Ana ekrana bırakılamadı."</string> <string name="external_drop_widget_pick_title" msgid="3486317258037690630">"Oluşturmak için widget seçin"</string> @@ -76,6 +77,7 @@ <string name="permlab_write_settings" msgid="3574213698004620587">"Ana ekran ayarlarını ve kısayollarını yaz"</string> <string name="permdesc_write_settings" msgid="5440712911516509985">"Uygulamaya, Ana ekrandaki ayarları ve kısayolları değiştirme izni verir."</string> <string name="gadget_error_text" msgid="6081085226050792095">"Widget yüklenirken sorun oluştu"</string> + <string name="gadget_setup_text" msgid="8274003207686040488">"Kurulum"</string> <string name="uninstall_system_app_text" msgid="4172046090762920660">"Bu bir sistem uygulamasıdır ve yüklemesi kaldırılamaz."</string> <string name="dream_name" msgid="1530253749244328964">"Roket Fırlatıcı"</string> <string name="folder_hint_text" msgid="6617836969016293992">"Adsız Klasör"</string> @@ -95,6 +97,9 @@ <string name="migration_cling_use_default" msgid="2626475813981258626">"VARSAYILANI KULLAN"</string> <string name="workspace_cling_title" msgid="5626202359865825661">"Alanınızı düzenleyin"</string> <string name="workspace_cling_move_item" msgid="528201129978005352">"Duvar kağıdını, widget\'ları ve ayarları yönetmek için arka plana uzun basın."</string> + <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Duvar kağıtları, widget\'lar ve ayarlar"</string> + <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"Özelleştirmek için arka plana dokunun ve basılı tutun"</string> + <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"TAMAM"</string> <string name="folder_cling_title" msgid="3894908818693254164">"İşte bir klasör"</string> <string name="folder_cling_create_folder" msgid="6158215559475836131">"Buna benzer bir klasör oluşturmak için uygulamaya uzun basın ve sonra uygulamayı başka bir uygulamanın üzerine taşıyın."</string> <string name="cling_dismiss" msgid="8962359497601507581">"Tamam"</string> @@ -107,4 +112,14 @@ <string name="widget_button_text" msgid="2880537293434387943">"Widget\'lar"</string> <string name="wallpaper_button_text" msgid="8404103075899945851">"Duvar Kağıtları"</string> <string name="settings_button_text" msgid="8119458837558863227">"Ayarlar"</string> + <string name="package_state_enqueued" msgid="6227252464303085641">"Bekliyor"</string> + <string name="package_state_downloading" msgid="4088770468458724721">"İndiriliyor"</string> + <string name="package_state_installing" msgid="7588193972189849870">"Yükleniyor"</string> + <string name="package_state_unknown" msgid="7592128424511031410">"Bilinmiyor"</string> + <string name="package_state_error" msgid="7672093962724223588">"Geri yüklenmedi"</string> + <string name="abandoned_clean_all" msgid="5256770727689657618">"Tümünü Kaldır"</string> + <string name="abandoned_clean_this" msgid="7610119707847920412">"Kaldır"</string> + <string name="abandoned_search" msgid="891119232568284442">"Ara"</string> + <string name="abandoned_promises_title" msgid="7096178467971716750">"Bu uygulama yüklü değil"</string> + <string name="abandoned_promise_explanation" msgid="3990027586878167529">"Bu simgenin uygulaması yüklü değil. Uygulamayı kaldırabilir veya arayıp manuel olarak yükleyebilirsiniz."</string> </resources> diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml index f266eeab5..e5b5cd8d2 100644 --- a/res/values-uk/strings.xml +++ b/res/values-uk/strings.xml @@ -23,7 +23,8 @@ <string name="home" msgid="7658288663002113681">"Головний екран"</string> <string name="uid_name" msgid="7820867637514617527">"Базові програми Android"</string> <string name="folder_name" msgid="7371454440695724752"></string> - <string name="activity_not_found" msgid="8071924732094499514">"Програму не встановлено."</string> + <string name="activity_not_found" msgid="8071924732094499514">"Додаток видалено."</string> + <string name="safemode_shortcut_error" msgid="9160126848219158407">"Завантажений додаток вимкнено в безпечному режимі"</string> <string name="widgets_tab_label" msgid="2921133187116603919">"Віджети"</string> <string name="widget_adder" msgid="3201040140710381657">"Віджети"</string> <string name="toggle_weight_watcher" msgid="5645299835184636119">"Показати пам’ять"</string> @@ -37,7 +38,7 @@ <string name="rename_action" msgid="5559600076028658757">"OК"</string> <string name="cancel_action" msgid="7009134900002915310">"Скасувати"</string> <string name="menu_item_add_item" msgid="1264911265836810421">"Додати на головний екран"</string> - <string name="group_applications" msgid="3797214114206693605">"Програми"</string> + <string name="group_applications" msgid="3797214114206693605">"Додатки"</string> <string name="group_shortcuts" msgid="6012256992764410535">"Ярлики"</string> <string name="group_widgets" msgid="1569030723286851002">"Віджети"</string> <string name="completely_out_of_space" msgid="6106288382070760318">"На головних екранах більше немає місця."</string> @@ -49,7 +50,7 @@ <string name="shortcut_duplicate" msgid="9167217446062498127">"Ярлик \"<xliff:g id="NAME">%s</xliff:g>\" уже існує."</string> <string name="title_select_shortcut" msgid="6680642571148153868">"Вибрати ярлик"</string> <string name="title_select_application" msgid="3280812711670683644">"Вибрати програму"</string> - <string name="all_apps_button_label" msgid="9110807029020582876">"Програми"</string> + <string name="all_apps_button_label" msgid="9110807029020582876">"Додатки"</string> <string name="all_apps_home_button_label" msgid="252062713717058851">"Головний екран"</string> <string name="delete_zone_label_workspace" msgid="4009607676751398685">"Вилучити"</string> <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"Видалити"</string> @@ -58,7 +59,7 @@ <string name="info_target_label" msgid="8053346143994679532">"Про програму"</string> <string name="accessibility_search_button" msgid="1628520399424565142">"Пошук"</string> <string name="accessibility_voice_search_button" msgid="4637324840434406584">"Голосовий пошук"</string> - <string name="accessibility_all_apps_button" msgid="2603132375383800483">"Програми"</string> + <string name="accessibility_all_apps_button" msgid="2603132375383800483">"Додатки"</string> <string name="accessibility_delete_button" msgid="6466114477993744621">"Вилучити"</string> <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"Видалити оновлення"</string> <string name="cab_menu_delete_app" msgid="7435191475867183689">"Видалити програму"</string> @@ -76,6 +77,7 @@ <string name="permlab_write_settings" msgid="3574213698004620587">"записувати налаштування та ярлики головного екрана"</string> <string name="permdesc_write_settings" msgid="5440712911516509985">"Дозволяє програмі змінювати налаштування та ярлики на головному екрані."</string> <string name="gadget_error_text" msgid="6081085226050792095">"Проблема із завантаженням віджета"</string> + <string name="gadget_setup_text" msgid="8274003207686040488">"Налаштування"</string> <string name="uninstall_system_app_text" msgid="4172046090762920660">"Це системна програма, її неможливо видалити."</string> <string name="dream_name" msgid="1530253749244328964">"Rocket Launcher"</string> <string name="folder_hint_text" msgid="6617836969016293992">"Папка без назви"</string> @@ -95,6 +97,9 @@ <string name="migration_cling_use_default" msgid="2626475813981258626">"ПАНЕЛЬ ЗАПУСКУ ЗА УМОВЧАННЯМ"</string> <string name="workspace_cling_title" msgid="5626202359865825661">"Організуйте робочий простір"</string> <string name="workspace_cling_move_item" msgid="528201129978005352">"Натисніть і утримуйте фон, щоб керувати фоновим малюнком, віджетами та налаштуваннями."</string> + <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Фонові малюнки, віджети й налаштування"</string> + <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"Натисніть і втримуйте фон, щоб налаштувати робочу область"</string> + <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"ЗРОЗУМІЛО"</string> <string name="folder_cling_title" msgid="3894908818693254164">"Це папка"</string> <string name="folder_cling_create_folder" msgid="6158215559475836131">"Щоб створити папку, натисніть і утримуйте програму, а потім перетягніть її на іншу."</string> <string name="cling_dismiss" msgid="8962359497601507581">"OК"</string> @@ -107,4 +112,14 @@ <string name="widget_button_text" msgid="2880537293434387943">"Віджети"</string> <string name="wallpaper_button_text" msgid="8404103075899945851">"Фонові малюнки"</string> <string name="settings_button_text" msgid="8119458837558863227">"Налаштування"</string> + <string name="package_state_enqueued" msgid="6227252464303085641">"Очікування"</string> + <string name="package_state_downloading" msgid="4088770468458724721">"Завантаження"</string> + <string name="package_state_installing" msgid="7588193972189849870">"Встановлення"</string> + <string name="package_state_unknown" msgid="7592128424511031410">"Невідомо"</string> + <string name="package_state_error" msgid="7672093962724223588">"Не відновлено"</string> + <string name="abandoned_clean_all" msgid="5256770727689657618">"Видалити всі"</string> + <string name="abandoned_clean_this" msgid="7610119707847920412">"Видалити"</string> + <string name="abandoned_search" msgid="891119232568284442">"Шукати"</string> + <string name="abandoned_promises_title" msgid="7096178467971716750">"Цей додаток не встановлено"</string> + <string name="abandoned_promise_explanation" msgid="3990027586878167529">"Додаток для цього значка не встановлено. Можна видалити значок або знайти додаток і встановити його вручну."</string> </resources> diff --git a/res/values-ur-rPK/strings.xml b/res/values-ur-rPK/strings.xml new file mode 100644 index 000000000..33b502e9b --- /dev/null +++ b/res/values-ur-rPK/strings.xml @@ -0,0 +1,122 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +* Copyright (C) 2008 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. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="application_name" msgid="5181331383435256801">"Launcher3"</string> + <string name="home" msgid="7658288663002113681">"ہوم"</string> + <string name="uid_name" msgid="7820867637514617527">"Android کور ایپس"</string> + <string name="folder_name" msgid="7371454440695724752"></string> + <string name="activity_not_found" msgid="8071924732094499514">"ایپ انسٹال نہیں ہے۔"</string> + <!-- no translation found for safemode_shortcut_error (9160126848219158407) --> + <skip /> + <string name="widgets_tab_label" msgid="2921133187116603919">"ویجیٹس"</string> + <string name="widget_adder" msgid="3201040140710381657">"ویجیٹس"</string> + <string name="toggle_weight_watcher" msgid="5645299835184636119">"Mem دکھائیں"</string> + <string name="long_press_widget_to_add" msgid="7699152356777458215">"کوئی ویجیٹ منتخب کرنے کیلئے ٹچ کریں اور پکڑے رہیں۔"</string> + <string name="market" msgid="2619650989819296998">"خریداری کریں"</string> + <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string> + <string name="external_drop_widget_error" msgid="3165821058322217155">"آئٹم کو اس ہوم اسکرین پر ڈراپ نہیں کیا جا سکا۔"</string> + <string name="external_drop_widget_pick_title" msgid="3486317258037690630">"بنانے کیلئے ویجیٹ منتخب کریں"</string> + <string name="rename_folder_label" msgid="3727762225964550653">"فولڈر کا نام"</string> + <string name="rename_folder_title" msgid="3771389277707820891">"فولڈر کا نام تبدیل کریں"</string> + <string name="rename_action" msgid="5559600076028658757">"ٹھیک ہے"</string> + <string name="cancel_action" msgid="7009134900002915310">"منسوخ کریں"</string> + <string name="menu_item_add_item" msgid="1264911265836810421">"ہوم اسکرین میں شامل کریں"</string> + <string name="group_applications" msgid="3797214114206693605">"ایپس"</string> + <string name="group_shortcuts" msgid="6012256992764410535">"شارٹ کٹس"</string> + <string name="group_widgets" msgid="1569030723286851002">"ویجیٹس"</string> + <string name="completely_out_of_space" msgid="6106288382070760318">"آپ کی ہوم اسکرینوں پر مزید کوئی گنجائش نہیں ہے۔"</string> + <string name="out_of_space" msgid="4691004494942118364">"اس ہوم اسکرین پر مزید کوئی گنجائش نہیں ہے۔"</string> + <string name="hotseat_out_of_space" msgid="7448809638125333693">"پسندیدہ ٹرے میں مزید کوئی گنجائش نہیں ہے"</string> + <string name="invalid_hotseat_item" msgid="5779907847267573691">"یہ ویجیٹ پسندیدہ ٹرے کیلئے کافی بڑا ہے"</string> + <string name="shortcut_installed" msgid="1701742129426969556">"شارٹ کٹ \"<xliff:g id="NAME">%s</xliff:g>\" بنایا گیا۔"</string> + <string name="shortcut_uninstalled" msgid="8176767991305701821">"شارٹ کٹ \"<xliff:g id="NAME">%s</xliff:g>\" ہٹا دیا گیا۔"</string> + <string name="shortcut_duplicate" msgid="9167217446062498127">"شارٹ کٹ \"<xliff:g id="NAME">%s</xliff:g>\" پہلے سے موجود ہے۔"</string> + <string name="title_select_shortcut" msgid="6680642571148153868">"شارٹ کٹ منتخب کریں"</string> + <string name="title_select_application" msgid="3280812711670683644">"ایپ منتخب کریں"</string> + <string name="all_apps_button_label" msgid="9110807029020582876">"ایپس"</string> + <string name="all_apps_home_button_label" msgid="252062713717058851">"ہوم"</string> + <string name="delete_zone_label_workspace" msgid="4009607676751398685">"ہٹائیں"</string> + <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"اَن انسٹال کریں"</string> + <string name="delete_target_label" msgid="1822697352535677073">"ہٹائیں"</string> + <string name="delete_target_uninstall_label" msgid="5100785476250872595">"اَن انسٹال کریں"</string> + <string name="info_target_label" msgid="8053346143994679532">"ایپ کی معلومات"</string> + <string name="accessibility_search_button" msgid="1628520399424565142">"تلاش کریں"</string> + <string name="accessibility_voice_search_button" msgid="4637324840434406584">"صوتی تلاش"</string> + <string name="accessibility_all_apps_button" msgid="2603132375383800483">"ایپس"</string> + <string name="accessibility_delete_button" msgid="6466114477993744621">"ہٹائیں"</string> + <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"اپ ڈیٹ اَن انسٹال کریں"</string> + <string name="cab_menu_delete_app" msgid="7435191475867183689">"ایپ کو اَن انسٹال کریں"</string> + <string name="cab_menu_app_info" msgid="8593722221450362342">"ایپ کی تفصیلات"</string> + <string name="cab_app_selection_text" msgid="374688303047985416">"1 ایپ منتخب کی گئی"</string> + <string name="cab_widget_selection_text" msgid="1833458597831541241">"1 ویجیٹ منتخب کیا گیا"</string> + <string name="cab_folder_selection_text" msgid="7999992513806132118">"1 فولڈر منتخب کیا گیا"</string> + <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"1 شارٹ کٹ منتخب کیا گیا"</string> + <string name="permlab_install_shortcut" msgid="5632423390354674437">"شارٹ کٹس انسٹال کریں"</string> + <string name="permdesc_install_shortcut" msgid="923466509822011139">"کسی ایپ کو صارف کی مداخلت کے بغیر شارٹ کٹس شامل کرنے کی اجازت دیتا ہے۔"</string> + <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"شارٹ کٹس کو اَن انسٹال کریں"</string> + <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"ایپ کو صارف کی مداخلت کے بغیر شارٹ کٹس ہٹانے کی اجازت دیتا ہے۔"</string> + <string name="permlab_read_settings" msgid="1941457408239617576">"ہوم ترتیبات اور شارٹ کٹس کو پڑھیں"</string> + <string name="permdesc_read_settings" msgid="5833423719057558387">"ایپ کو ہوم میں ترتیبات اور شارٹ کٹس کو پڑھنے کی اجازت دیتا ہے۔"</string> + <string name="permlab_write_settings" msgid="3574213698004620587">"ہوم ترتیبات اور شارٹ کٹس کو لکھیں"</string> + <string name="permdesc_write_settings" msgid="5440712911516509985">"ایپ کو ہوم میں ترتیبات اور شارٹ کٹس کو تبدیل کرنے کی اجازت دیتا ہے۔"</string> + <string name="gadget_error_text" msgid="6081085226050792095">"ویجیٹ کو لوڈ کرنے میں مسئلہ"</string> + <string name="uninstall_system_app_text" msgid="4172046090762920660">"یہ ایک سسٹم ایپ ہے اور اسے اَن انسٹال نہیں کیا جا سکتا ہے۔"</string> + <string name="dream_name" msgid="1530253749244328964">"راکٹ لانچر"</string> + <string name="folder_hint_text" msgid="6617836969016293992">"بلا نام فولڈر"</string> + <string name="workspace_description_format" msgid="2950174241104043327">"ہوم اسکرین %1$d"</string> + <string name="default_scroll_format" msgid="7475544710230993317">"صفحہ %1$d از %2$d"</string> + <string name="workspace_scroll_format" msgid="8458889198184077399">"ہوم اسکرین %1$d از %2$d"</string> + <string name="apps_customize_apps_scroll_format" msgid="370005296147130238">"ایپس کا صفحہ %1$d از %2$d"</string> + <string name="apps_customize_widgets_scroll_format" msgid="3106209519974971521">"ویجیٹس کا صفحہ %1$d از %2$d"</string> + <string name="first_run_cling_title" msgid="2459738000155917941">"خوش آمدید"</string> + <string name="first_run_cling_description" msgid="6447072552696253358">"ہوم سکرین مرضی کے مطابق بنائیں۔"</string> + <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string> + <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string> + <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"ایپس اور فولڈرز کیلئے مزید اسکرینیں بنائیں"</string> + <string name="migration_cling_title" msgid="9181776667882933767">"اپنے ایپ آئیکنز کو کاپی کریں"</string> + <string name="migration_cling_description" msgid="2752413805582227644">"اپنی پرانی ہوم اسکرینوں سے آئیکنز اور فولڈرز درآمد کریں؟"</string> + <string name="migration_cling_copy_apps" msgid="946331230090919440">"آئیکنز کاپی کریں"</string> + <string name="migration_cling_use_default" msgid="2626475813981258626">"نئے سرے سے شروع کریں"</string> + <string name="workspace_cling_title" msgid="5626202359865825661">"اپنی جگہ کو منظم کریں"</string> + <string name="workspace_cling_move_item" msgid="528201129978005352">"وال پیپر، ویجیٹس اور ترتیبات کا نظم کرنے کیلئے پس منظر کو ٹچ کریں اور پکڑ کر رکھیں۔"</string> + <string name="folder_cling_title" msgid="3894908818693254164">"یہ ہے ایک فولڈر"</string> + <string name="folder_cling_create_folder" msgid="6158215559475836131">"اس طرح کا ایک بنانے کیلئے، کسی ایپ کو ٹچ کریں اور پکڑ کر رکھیں، پھر اسے کسی دوسرے میں منتقل کریں۔"</string> + <string name="cling_dismiss" msgid="8962359497601507581">"ٹھیک ہے"</string> + <string name="folder_opened" msgid="94695026776264709">"فولڈر کھولا گیا، <xliff:g id="WIDTH">%1$d</xliff:g> × <xliff:g id="HEIGHT">%2$d</xliff:g>"</string> + <string name="folder_tap_to_close" msgid="1884479294466410023">"فولڈر بند کرنے کیلئے ٹچ کریں"</string> + <string name="folder_tap_to_rename" msgid="9191075570492871147">"نام کی تبدیلی محفوظ کرنے کیلئے ٹچ کریں"</string> + <string name="folder_closed" msgid="4100806530910930934">"فولڈر بند ہو گیا"</string> + <string name="folder_renamed" msgid="1794088362165669656">"فولڈر کا نام تبدیل کر کے <xliff:g id="NAME">%1$s</xliff:g> کر دیا گیا"</string> + <string name="folder_name_format" msgid="6629239338071103179">"فولڈر: <xliff:g id="NAME">%1$s</xliff:g>"</string> + <string name="widget_button_text" msgid="2880537293434387943">"ویجیٹس"</string> + <string name="wallpaper_button_text" msgid="8404103075899945851">"وال پیپرز"</string> + <string name="settings_button_text" msgid="8119458837558863227">"ترتیبات"</string> + <string name="package_state_enqueued" msgid="6227252464303085641">"منتظر"</string> + <string name="package_state_downloading" msgid="4088770468458724721">"ڈاؤن لوڈ کیا جا رہا ہے"</string> + <string name="package_state_installing" msgid="7588193972189849870">"انسٹال کیا جا رہا ہے"</string> + <string name="package_state_unknown" msgid="7592128424511031410">"نامعلوم"</string> + <string name="package_state_error" msgid="7672093962724223588">"بحال نہیں ہوا"</string> + <string name="abandoned_clean_all" msgid="5256770727689657618">"سبھی کو ہٹا دیں"</string> + <string name="abandoned_clean_this" msgid="7610119707847920412">"ہٹائیں"</string> + <string name="abandoned_search" msgid="891119232568284442">"تلاش کریں"</string> + <string name="abandoned_promises_title" msgid="7096178467971716750">"یہ ایپ انسٹال کردہ نہیں ہے"</string> + <string name="abandoned_promise_explanation" msgid="3990027586878167529">"اس آئیکن کیلئے ایپ انسٹال کردہ نہیں ہے۔ آپ اسے ہٹا سکتے ہیں یا ایپ کو تلاش کر سکتے اور دستی طور پر اسے انسٹال کر سکتے ہیں۔"</string> +</resources> diff --git a/res/values-uz-rUZ/strings.xml b/res/values-uz-rUZ/strings.xml new file mode 100644 index 000000000..791f6c888 --- /dev/null +++ b/res/values-uz-rUZ/strings.xml @@ -0,0 +1,122 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +* Copyright (C) 2008 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. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="application_name" msgid="5181331383435256801">"Ishga tushirgich3"</string> + <string name="home" msgid="7658288663002113681">"Uy"</string> + <string name="uid_name" msgid="7820867637514617527">"Androidga asoslangan dasturlar"</string> + <string name="folder_name" msgid="7371454440695724752"></string> + <string name="activity_not_found" msgid="8071924732094499514">"Ilova o‘rnatilmadi."</string> + <!-- no translation found for safemode_shortcut_error (9160126848219158407) --> + <skip /> + <string name="widgets_tab_label" msgid="2921133187116603919">"Vidjetlar"</string> + <string name="widget_adder" msgid="3201040140710381657">"Vidjetlar"</string> + <string name="toggle_weight_watcher" msgid="5645299835184636119">"Xotirani ko‘rsatish"</string> + <string name="long_press_widget_to_add" msgid="7699152356777458215">"Vidjetni tanlash uchun bosib turing."</string> + <string name="market" msgid="2619650989819296998">"Do‘kon"</string> + <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string> + <string name="external_drop_widget_error" msgid="3165821058322217155">"Elementni ushbu \"Uy\" ekraniga tashlab bo‘lmadi."</string> + <string name="external_drop_widget_pick_title" msgid="3486317258037690630">"Yaratish uchun vidjet tanlang"</string> + <string name="rename_folder_label" msgid="3727762225964550653">"Jild nomi"</string> + <string name="rename_folder_title" msgid="3771389277707820891">"Jild nomini o‘zgartirish"</string> + <string name="rename_action" msgid="5559600076028658757">"OK"</string> + <string name="cancel_action" msgid="7009134900002915310">"Bekor qilish"</string> + <string name="menu_item_add_item" msgid="1264911265836810421">"Uy ekraniga qo‘shish"</string> + <string name="group_applications" msgid="3797214114206693605">"Ilovalar"</string> + <string name="group_shortcuts" msgid="6012256992764410535">"Yorliqlar"</string> + <string name="group_widgets" msgid="1569030723286851002">"Vidjetlar"</string> + <string name="completely_out_of_space" msgid="6106288382070760318">"Uy ekraningizda birorta ham xona yo‘q."</string> + <string name="out_of_space" msgid="4691004494942118364">"Uy ekranida bitta ham xona yo‘q."</string> + <string name="hotseat_out_of_space" msgid="7448809638125333693">"Ajratilganlarda birorta ham xona yo‘q"</string> + <string name="invalid_hotseat_item" msgid="5779907847267573691">"Ajratilganlar uchun ushbu vidjet juda katta"</string> + <string name="shortcut_installed" msgid="1701742129426969556">"\"<xliff:g id="NAME">%s</xliff:g>\" yorlig‘i yaratildi."</string> + <string name="shortcut_uninstalled" msgid="8176767991305701821">"\"<xliff:g id="NAME">%s</xliff:g>\" yorlig‘i o‘chirildi."</string> + <string name="shortcut_duplicate" msgid="9167217446062498127">"\"<xliff:g id="NAME">%s</xliff:g>\" yorlig‘i allaqachon mavjud."</string> + <string name="title_select_shortcut" msgid="6680642571148153868">"Yorliqni tanlash"</string> + <string name="title_select_application" msgid="3280812711670683644">"Ilovani tanlash"</string> + <string name="all_apps_button_label" msgid="9110807029020582876">"Ilovalar"</string> + <string name="all_apps_home_button_label" msgid="252062713717058851">"Uy"</string> + <string name="delete_zone_label_workspace" msgid="4009607676751398685">"O‘chirish"</string> + <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"O‘chirish"</string> + <string name="delete_target_label" msgid="1822697352535677073">"O‘chirish"</string> + <string name="delete_target_uninstall_label" msgid="5100785476250872595">"O‘chirish"</string> + <string name="info_target_label" msgid="8053346143994679532">"Ilova ma’lumoti"</string> + <string name="accessibility_search_button" msgid="1628520399424565142">"Izlash"</string> + <string name="accessibility_voice_search_button" msgid="4637324840434406584">"Ovozli qidiruv"</string> + <string name="accessibility_all_apps_button" msgid="2603132375383800483">"Ilovalar"</string> + <string name="accessibility_delete_button" msgid="6466114477993744621">"O‘chirish"</string> + <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"Yangilashni o‘chirish"</string> + <string name="cab_menu_delete_app" msgid="7435191475867183689">"Ilovani o‘chirish"</string> + <string name="cab_menu_app_info" msgid="8593722221450362342">"Ilova ma’lumotlari"</string> + <string name="cab_app_selection_text" msgid="374688303047985416">"1 ta ilova tanlandi"</string> + <string name="cab_widget_selection_text" msgid="1833458597831541241">"1 ta vidjet tanlandi"</string> + <string name="cab_folder_selection_text" msgid="7999992513806132118">"1 ta jild tanlandi"</string> + <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"1 ta yorliq tanlandi"</string> + <string name="permlab_install_shortcut" msgid="5632423390354674437">"yorliqlar o‘rnatish"</string> + <string name="permdesc_install_shortcut" msgid="923466509822011139">"Ilovalarga foydalanuvchidan so‘ramasdan yorliqlar qo‘shishga ruxsat beradi."</string> + <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"yorliqlarni o‘chirish"</string> + <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"Ilovaga foydalanuvchiga bildirmasdan yorliqlarni o‘chirish uchun ruxsat beradi."</string> + <string name="permlab_read_settings" msgid="1941457408239617576">"Uy sozlamalari va yorliqlarini o‘qish"</string> + <string name="permdesc_read_settings" msgid="5833423719057558387">"Ilovaga \"Uy\" ekranidagi yorliqlar va sozlamalarni o‘qish uchun ruxsat beradi."</string> + <string name="permlab_write_settings" msgid="3574213698004620587">"Uy sozlamalari va yorliqlarini yozish"</string> + <string name="permdesc_write_settings" msgid="5440712911516509985">"Ilovaga \"Uy\" ekranidagi yorliqlar va sozlamalrni o‘zgartirish uchun ruxsat beradi."</string> + <string name="gadget_error_text" msgid="6081085226050792095">"Vidjetni yuklashda muammo"</string> + <string name="uninstall_system_app_text" msgid="4172046090762920660">"Bu tizim ilovasi, shuning uchun o‘chirib bo‘lmaydi."</string> + <string name="dream_name" msgid="1530253749244328964">"Rocket Launcher"</string> + <string name="folder_hint_text" msgid="6617836969016293992">"Nomsiz jild"</string> + <string name="workspace_description_format" msgid="2950174241104043327">"Uy ekrani %1$d"</string> + <string name="default_scroll_format" msgid="7475544710230993317">"%2$ddan %1$d ta sahifa"</string> + <string name="workspace_scroll_format" msgid="8458889198184077399">"Uy ekrani %2$ddan %1$d"</string> + <string name="apps_customize_apps_scroll_format" msgid="370005296147130238">"Ilovalar sahifasi %2$ddan %1$d"</string> + <string name="apps_customize_widgets_scroll_format" msgid="3106209519974971521">"Vidjetlar sahifasi %2$ddan %1$d"</string> + <string name="first_run_cling_title" msgid="2459738000155917941">"Xush kelibsiz"</string> + <string name="first_run_cling_description" msgid="6447072552696253358">"O‘zingizni uyingizdagidek his qiling."</string> + <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string> + <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string> + <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"Ilovalar va jildlar uchun ko‘proq ekranlar yaratish"</string> + <string name="migration_cling_title" msgid="9181776667882933767">"Ilovangiz nishonchalaridan nusxa olish"</string> + <string name="migration_cling_description" msgid="2752413805582227644">"Eski \"Uy\" ekranlaringizdan jildlar va nishonchalar import qilinsinmi?"</string> + <string name="migration_cling_copy_apps" msgid="946331230090919440">"NISHONCHALARNI NUSXALASH"</string> + <string name="migration_cling_use_default" msgid="2626475813981258626">"YANGIDAN BOSHLASH"</string> + <string name="workspace_cling_title" msgid="5626202359865825661">"Joylaringizni boshqaring"</string> + <string name="workspace_cling_move_item" msgid="528201129978005352">"Fon rasmi, vidjet va sozlamalarni boshqarish uchun orqa fonga bosib turing"</string> + <string name="folder_cling_title" msgid="3894908818693254164">"Mana sizga jild"</string> + <string name="folder_cling_create_folder" msgid="6158215559475836131">"Bunga o‘xshaganini yaratish uchun bosib turing, keyin boshqasiga o‘ting."</string> + <string name="cling_dismiss" msgid="8962359497601507581">"OK"</string> + <string name="folder_opened" msgid="94695026776264709">"Jild ochildi, <xliff:g id="WIDTH">%1$d</xliff:g> ga <xliff:g id="HEIGHT">%2$d</xliff:g>"</string> + <string name="folder_tap_to_close" msgid="1884479294466410023">"Jildni yopish uchun bosing"</string> + <string name="folder_tap_to_rename" msgid="9191075570492871147">"O‘zgartirilgan nomni saqlash uchun bosing"</string> + <string name="folder_closed" msgid="4100806530910930934">"Jild yopildi"</string> + <string name="folder_renamed" msgid="1794088362165669656">"Jild nomi <xliff:g id="NAME">%1$s</xliff:g>ga o‘zgartirildi"</string> + <string name="folder_name_format" msgid="6629239338071103179">"Jild: <xliff:g id="NAME">%1$s</xliff:g>"</string> + <string name="widget_button_text" msgid="2880537293434387943">"Vidjetlar"</string> + <string name="wallpaper_button_text" msgid="8404103075899945851">"Orqa fon rasmlari"</string> + <string name="settings_button_text" msgid="8119458837558863227">"Sozlamalar"</string> + <string name="package_state_enqueued" msgid="6227252464303085641">"Kutilmoqda"</string> + <string name="package_state_downloading" msgid="4088770468458724721">"Yuklab olinmoqda"</string> + <string name="package_state_installing" msgid="7588193972189849870">"O‘rnatilmoqda"</string> + <string name="package_state_unknown" msgid="7592128424511031410">"Noma’lum"</string> + <string name="package_state_error" msgid="7672093962724223588">"Qayta tiklanmadi"</string> + <string name="abandoned_clean_all" msgid="5256770727689657618">"Barchasini o‘chirish"</string> + <string name="abandoned_clean_this" msgid="7610119707847920412">"O‘chirish"</string> + <string name="abandoned_search" msgid="891119232568284442">"Qidirish"</string> + <string name="abandoned_promises_title" msgid="7096178467971716750">"Ushbu ilova o‘rnatilmagan"</string> + <string name="abandoned_promise_explanation" msgid="3990027586878167529">"Ilova o‘rnatilmagan. Belgini o‘chirib tashlashingiz yoki ilovani topib, uni qo‘lda o‘rnatishingiz mumkin."</string> +</resources> diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml index 9d4ed413c..489123089 100644 --- a/res/values-vi/strings.xml +++ b/res/values-vi/strings.xml @@ -24,6 +24,7 @@ <string name="uid_name" msgid="7820867637514617527">"Ứng dụng lõi Android"</string> <string name="folder_name" msgid="7371454440695724752"></string> <string name="activity_not_found" msgid="8071924732094499514">"Ứng dụng chưa được cài đặt."</string> + <string name="safemode_shortcut_error" msgid="9160126848219158407">"Ứng dụng đã tải xuống bị tắt ở chế độ An toàn"</string> <string name="widgets_tab_label" msgid="2921133187116603919">"Tiện ích con"</string> <string name="widget_adder" msgid="3201040140710381657">"Tiện ích con"</string> <string name="toggle_weight_watcher" msgid="5645299835184636119">"Hiển thị bộ nhớ"</string> @@ -76,6 +77,7 @@ <string name="permlab_write_settings" msgid="3574213698004620587">"ghi cài đặt và lối tắt trên Màn hình chính"</string> <string name="permdesc_write_settings" msgid="5440712911516509985">"Cho phép ứng dụng thay đổi cài đặt và lối tắt trên Màn hình chính."</string> <string name="gadget_error_text" msgid="6081085226050792095">"Sự cố khi tải tiện ích con"</string> + <string name="gadget_setup_text" msgid="8274003207686040488">"Thiết lập"</string> <string name="uninstall_system_app_text" msgid="4172046090762920660">"Đây là ứng dụng hệ thống và không thể gỡ cài đặt."</string> <string name="dream_name" msgid="1530253749244328964">"Rocket Launcher"</string> <string name="folder_hint_text" msgid="6617836969016293992">"Thư mục chưa đặt tên"</string> @@ -95,6 +97,9 @@ <string name="migration_cling_use_default" msgid="2626475813981258626">"BẮT ĐẦU LÀM MỚI"</string> <string name="workspace_cling_title" msgid="5626202359865825661">"Sắp xếp không gian của bạn"</string> <string name="workspace_cling_move_item" msgid="528201129978005352">"Chạm và giữ nền để quản lý hình nền, tiện ích con và cài đặt."</string> + <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Hình nền, tiện ích và cài đặt"</string> + <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"Chạm và giữ nền để tùy chỉnh"</string> + <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"OK"</string> <string name="folder_cling_title" msgid="3894908818693254164">"Đây là một thư mục"</string> <string name="folder_cling_create_folder" msgid="6158215559475836131">"Để tạo thư mục như thế này, hãy chạm và giữ một ứng dụng, sau đó di chuyển ứng dụng đó lên trên một ứng dụng khác."</string> <string name="cling_dismiss" msgid="8962359497601507581">"OK"</string> @@ -107,4 +112,14 @@ <string name="widget_button_text" msgid="2880537293434387943">"Tiện ích con"</string> <string name="wallpaper_button_text" msgid="8404103075899945851">"Hình nền"</string> <string name="settings_button_text" msgid="8119458837558863227">"Cài đặt"</string> + <string name="package_state_enqueued" msgid="6227252464303085641">"Đang đợi"</string> + <string name="package_state_downloading" msgid="4088770468458724721">"Đang tải xuống"</string> + <string name="package_state_installing" msgid="7588193972189849870">"Đang cài đặt"</string> + <string name="package_state_unknown" msgid="7592128424511031410">"Không xác định"</string> + <string name="package_state_error" msgid="7672093962724223588">"Không được khôi phục"</string> + <string name="abandoned_clean_all" msgid="5256770727689657618">"Xóa tất cả"</string> + <string name="abandoned_clean_this" msgid="7610119707847920412">"Xóa"</string> + <string name="abandoned_search" msgid="891119232568284442">"Tìm kiếm"</string> + <string name="abandoned_promises_title" msgid="7096178467971716750">"Ứng dụng này chưa được cài đặt"</string> + <string name="abandoned_promise_explanation" msgid="3990027586878167529">"Ứng dụng cho biểu tượng này chưa được cài đặt. Bạn có thể xóa ứng dụng hoặc tìm kiếm và cài đặt ứng dụng theo cách thủ công."</string> </resources> diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml index 3a2638e34..3365581be 100644 --- a/res/values-zh-rCN/strings.xml +++ b/res/values-zh-rCN/strings.xml @@ -24,6 +24,7 @@ <string name="uid_name" msgid="7820867637514617527">"Android 核心应用"</string> <string name="folder_name" msgid="7371454440695724752"></string> <string name="activity_not_found" msgid="8071924732094499514">"未安装该应用。"</string> + <string name="safemode_shortcut_error" msgid="9160126848219158407">"安全模式下不允许使用下载的此应用"</string> <string name="widgets_tab_label" msgid="2921133187116603919">"小部件"</string> <string name="widget_adder" msgid="3201040140710381657">"小部件"</string> <string name="toggle_weight_watcher" msgid="5645299835184636119">"显示内存空间"</string> @@ -76,6 +77,7 @@ <string name="permlab_write_settings" msgid="3574213698004620587">"写入主屏幕设置和快捷方式"</string> <string name="permdesc_write_settings" msgid="5440712911516509985">"允许应用更改主屏幕中的设置和快捷方式。"</string> <string name="gadget_error_text" msgid="6081085226050792095">"加载小部件时出现问题"</string> + <string name="gadget_setup_text" msgid="8274003207686040488">"设置"</string> <string name="uninstall_system_app_text" msgid="4172046090762920660">"这是系统应用,无法卸载。"</string> <string name="dream_name" msgid="1530253749244328964">"火箭发射器"</string> <string name="folder_hint_text" msgid="6617836969016293992">"未命名文件夹"</string> @@ -95,6 +97,9 @@ <string name="migration_cling_use_default" msgid="2626475813981258626">"使用全新配置"</string> <string name="workspace_cling_title" msgid="5626202359865825661">"整理您的空间"</string> <string name="workspace_cling_move_item" msgid="528201129978005352">"触摸并按住背景,即可管理壁纸、小部件和设置。"</string> + <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"壁纸、小部件和设置"</string> + <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"触摸并按住背景,即可进行个性化设置"</string> + <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"知道了"</string> <string name="folder_cling_title" msgid="3894908818693254164">"这是一个文件夹"</string> <string name="folder_cling_create_folder" msgid="6158215559475836131">"要创建一个类似的文件夹,请触摸并按住某个应用,然后将其移至另一个应用上。"</string> <string name="cling_dismiss" msgid="8962359497601507581">"确定"</string> @@ -107,4 +112,14 @@ <string name="widget_button_text" msgid="2880537293434387943">"小部件"</string> <string name="wallpaper_button_text" msgid="8404103075899945851">"壁纸"</string> <string name="settings_button_text" msgid="8119458837558863227">"设置"</string> + <string name="package_state_enqueued" msgid="6227252464303085641">"正在等待"</string> + <string name="package_state_downloading" msgid="4088770468458724721">"正在下载"</string> + <string name="package_state_installing" msgid="7588193972189849870">"正在安装"</string> + <string name="package_state_unknown" msgid="7592128424511031410">"未知"</string> + <string name="package_state_error" msgid="7672093962724223588">"无法还原"</string> + <string name="abandoned_clean_all" msgid="5256770727689657618">"全部移除"</string> + <string name="abandoned_clean_this" msgid="7610119707847920412">"移除"</string> + <string name="abandoned_search" msgid="891119232568284442">"搜索"</string> + <string name="abandoned_promises_title" msgid="7096178467971716750">"未安装此应用"</string> + <string name="abandoned_promise_explanation" msgid="3990027586878167529">"未安装此图标对应的应用。您可以移除此图标,也可以尝试搜索相应的应用并手动安装。"</string> </resources> diff --git a/res/values-zh-rHK/strings.xml b/res/values-zh-rHK/strings.xml index cad95f27c..457d5be9e 100644 --- a/res/values-zh-rHK/strings.xml +++ b/res/values-zh-rHK/strings.xml @@ -24,6 +24,7 @@ <string name="uid_name" msgid="7820867637514617527">"Android 核心應用程式"</string> <string name="folder_name" msgid="7371454440695724752"></string> <string name="activity_not_found" msgid="8071924732094499514">"尚未安裝應用程式。"</string> + <string name="safemode_shortcut_error" msgid="9160126848219158407">"在安全模式中無法使用「已下載的應用程式」功能"</string> <string name="widgets_tab_label" msgid="2921133187116603919">"小工具"</string> <string name="widget_adder" msgid="3201040140710381657">"小工具"</string> <string name="toggle_weight_watcher" msgid="5645299835184636119">"顯示記憶體"</string> @@ -68,14 +69,15 @@ <string name="cab_folder_selection_text" msgid="7999992513806132118">"已選取 1 個資料夾"</string> <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"已選取 1 個捷徑"</string> <string name="permlab_install_shortcut" msgid="5632423390354674437">"安裝捷徑"</string> - <string name="permdesc_install_shortcut" msgid="923466509822011139">"允許應用程式無需用戶許可也可新增捷徑。"</string> + <string name="permdesc_install_shortcut" msgid="923466509822011139">"允許應用程式無需使用者許可也可新增捷徑。"</string> <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"解除安裝捷徑"</string> - <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"允許應用程式無需用戶許可也可移除捷徑。"</string> + <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"允許應用程式無需使用者許可也可移除捷徑。"</string> <string name="permlab_read_settings" msgid="1941457408239617576">"讀取主畫面的設定和捷徑"</string> <string name="permdesc_read_settings" msgid="5833423719057558387">"允許應用程式讀取主畫面中的設定和捷徑。"</string> <string name="permlab_write_settings" msgid="3574213698004620587">"寫入主畫面的設定和捷徑"</string> <string name="permdesc_write_settings" msgid="5440712911516509985">"允許應用程式更改主畫面中的設定和捷徑。"</string> <string name="gadget_error_text" msgid="6081085226050792095">"載入小工具時發生問題"</string> + <string name="gadget_setup_text" msgid="8274003207686040488">"設定"</string> <string name="uninstall_system_app_text" msgid="4172046090762920660">"這是系統應用程式,無法將其解除安裝。"</string> <string name="dream_name" msgid="1530253749244328964">"Rocket Launcher"</string> <string name="folder_hint_text" msgid="6617836969016293992">"未命名的資料夾"</string> @@ -95,6 +97,9 @@ <string name="migration_cling_use_default" msgid="2626475813981258626">"重新開始"</string> <string name="workspace_cling_title" msgid="5626202359865825661">"管理您的空間"</string> <string name="workspace_cling_move_item" msgid="528201129978005352">"輕觸並按住背景,即可管理桌布、小工具和設定。"</string> + <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"桌布、小工具和設定"</string> + <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"輕觸並按住背景即可自訂"</string> + <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"知道了"</string> <string name="folder_cling_title" msgid="3894908818693254164">"資料夾顯示如下"</string> <string name="folder_cling_create_folder" msgid="6158215559475836131">"如要建立類似的資料夾,請輕觸並按住某個應用程式,然後疊到另一個應用程式之上。"</string> <string name="cling_dismiss" msgid="8962359497601507581">"確定"</string> @@ -107,4 +112,14 @@ <string name="widget_button_text" msgid="2880537293434387943">"小工具"</string> <string name="wallpaper_button_text" msgid="8404103075899945851">"桌布"</string> <string name="settings_button_text" msgid="8119458837558863227">"設定"</string> + <string name="package_state_enqueued" msgid="6227252464303085641">"等候中"</string> + <string name="package_state_downloading" msgid="4088770468458724721">"下載中"</string> + <string name="package_state_installing" msgid="7588193972189849870">"安裝中"</string> + <string name="package_state_unknown" msgid="7592128424511031410">"不明"</string> + <string name="package_state_error" msgid="7672093962724223588">"無法還原"</string> + <string name="abandoned_clean_all" msgid="5256770727689657618">"全部移除"</string> + <string name="abandoned_clean_this" msgid="7610119707847920412">"移除"</string> + <string name="abandoned_search" msgid="891119232568284442">"搜尋"</string> + <string name="abandoned_promises_title" msgid="7096178467971716750">"尚未安裝這個應用程式"</string> + <string name="abandoned_promise_explanation" msgid="3990027586878167529">"您尚未安裝這個圖示代表的應用程式。您可以移除這個圖示,也可以搜尋該應用程式並手動安裝。"</string> </resources> diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml index 5f482430e..2d400596f 100644 --- a/res/values-zh-rTW/strings.xml +++ b/res/values-zh-rTW/strings.xml @@ -24,6 +24,7 @@ <string name="uid_name" msgid="7820867637514617527">"Android 核心應用程式"</string> <string name="folder_name" msgid="7371454440695724752"></string> <string name="activity_not_found" msgid="8071924732094499514">"應用程式未安裝。"</string> + <string name="safemode_shortcut_error" msgid="9160126848219158407">"在安全模式中無法使用「已下載的應用程式」功能"</string> <string name="widgets_tab_label" msgid="2921133187116603919">"小工具"</string> <string name="widget_adder" msgid="3201040140710381657">"小工具"</string> <string name="toggle_weight_watcher" msgid="5645299835184636119">"顯示記憶體"</string> @@ -76,6 +77,7 @@ <string name="permlab_write_settings" msgid="3574213698004620587">"寫入主螢幕設定和捷徑"</string> <string name="permdesc_write_settings" msgid="5440712911516509985">"允許應用程式變更主螢幕中的設定和捷徑。"</string> <string name="gadget_error_text" msgid="6081085226050792095">"載入小工具時發生問題"</string> + <string name="gadget_setup_text" msgid="8274003207686040488">"設定"</string> <string name="uninstall_system_app_text" msgid="4172046090762920660">"這是系統應用程式,不可解除安裝。"</string> <string name="dream_name" msgid="1530253749244328964">"Rocket Launcher"</string> <string name="folder_hint_text" msgid="6617836969016293992">"未命名的資料夾"</string> @@ -95,6 +97,9 @@ <string name="migration_cling_use_default" msgid="2626475813981258626">"重新開始"</string> <string name="workspace_cling_title" msgid="5626202359865825661">"管理您的空間"</string> <string name="workspace_cling_move_item" msgid="528201129978005352">"輕觸並按住背景,即可管理桌布、小工具和設定。"</string> + <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"桌布、小工具和設定"</string> + <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"輕觸並按住背景即可自訂"</string> + <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"知道了"</string> <string name="folder_cling_title" msgid="3894908818693254164">"資料夾顯示如下"</string> <string name="folder_cling_create_folder" msgid="6158215559475836131">"如要建立類似的資料夾,請輕觸並按住應用程式,然後將應用程式疊放在另一個應用程式上。"</string> <string name="cling_dismiss" msgid="8962359497601507581">"確定"</string> @@ -107,4 +112,14 @@ <string name="widget_button_text" msgid="2880537293434387943">"小工具"</string> <string name="wallpaper_button_text" msgid="8404103075899945851">"桌布"</string> <string name="settings_button_text" msgid="8119458837558863227">"設定"</string> + <string name="package_state_enqueued" msgid="6227252464303085641">"等待中"</string> + <string name="package_state_downloading" msgid="4088770468458724721">"下載中…"</string> + <string name="package_state_installing" msgid="7588193972189849870">"安裝中"</string> + <string name="package_state_unknown" msgid="7592128424511031410">"不明"</string> + <string name="package_state_error" msgid="7672093962724223588">"無法還原"</string> + <string name="abandoned_clean_all" msgid="5256770727689657618">"全部移除"</string> + <string name="abandoned_clean_this" msgid="7610119707847920412">"移除"</string> + <string name="abandoned_search" msgid="891119232568284442">"搜尋"</string> + <string name="abandoned_promises_title" msgid="7096178467971716750">"尚未安裝這個應用程式"</string> + <string name="abandoned_promise_explanation" msgid="3990027586878167529">"您尚未安裝這個圖示代表的應用程式。您可以移除這個圖示,也可以搜尋該應用程式並手動安裝。"</string> </resources> diff --git a/res/values-zu/strings.xml b/res/values-zu/strings.xml index e982eb419..89cd5cc12 100644 --- a/res/values-zu/strings.xml +++ b/res/values-zu/strings.xml @@ -24,6 +24,7 @@ <string name="uid_name" msgid="7820867637514617527">"Izinhlelo zokusebenza ze-Android Core"</string> <string name="folder_name" msgid="7371454440695724752"></string> <string name="activity_not_found" msgid="8071924732094499514">"Uhlelo lokusebenza alufakiwe."</string> + <string name="safemode_shortcut_error" msgid="9160126848219158407">"Uhlelo lokusebenza olulandiwe lukhutshaziwe kumodi ephephile"</string> <string name="widgets_tab_label" msgid="2921133187116603919">"Amawijethi"</string> <string name="widget_adder" msgid="3201040140710381657">"Amawijethi"</string> <string name="toggle_weight_watcher" msgid="5645299835184636119">"Bonisa i-Mem"</string> @@ -76,6 +77,7 @@ <string name="permlab_write_settings" msgid="3574213698004620587">"bhala izilungiselelo zokuthi Ikhaya nezinqamuleli"</string> <string name="permdesc_write_settings" msgid="5440712911516509985">"Ivumela uhlelo lokusebenza ukuthi lushintshe izilungiselelo nezinqamuleli Ekhaya."</string> <string name="gadget_error_text" msgid="6081085226050792095">"Inkinga yokulayisha iwijethi"</string> + <string name="gadget_setup_text" msgid="8274003207686040488">"Ukumisa"</string> <string name="uninstall_system_app_text" msgid="4172046090762920660">"Lolu uhlelo lokusebenza lwesistimu futhi alikwazi ukukhishwa."</string> <string name="dream_name" msgid="1530253749244328964">"Isiqalisi se-Rocket"</string> <string name="folder_hint_text" msgid="6617836969016293992">"Ifolda engenagama"</string> @@ -95,6 +97,9 @@ <string name="migration_cling_use_default" msgid="2626475813981258626">"QALISA KABUSHA"</string> <string name="workspace_cling_title" msgid="5626202359865825661">"Hlela isikhala sakho"</string> <string name="workspace_cling_move_item" msgid="528201129978005352">"Thinta uphinde ubambe okungemuva ukuze uphathe isithombe sangemuva, amawijethi nezilungiselelo."</string> + <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Izithombe zangemuva, amawijethi, nezilungiselelo"</string> + <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"Thinta uphinde ubambe ingemuva ukuze wenze ngokwezifiso"</string> + <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"NGIYITHOLILE"</string> <string name="folder_cling_title" msgid="3894908818693254164">"Nayi ifolda"</string> <string name="folder_cling_create_folder" msgid="6158215559475836131">"Ukuze udale eyodwa efana nale, thinta uphinde ubambe uhlelo lokusebenza, bese ulidlulisa ngaphezulu kwelinye."</string> <string name="cling_dismiss" msgid="8962359497601507581">"KULUNGILE"</string> @@ -107,4 +112,14 @@ <string name="widget_button_text" msgid="2880537293434387943">"Amawijethi"</string> <string name="wallpaper_button_text" msgid="8404103075899945851">"Izithombe zangemuva"</string> <string name="settings_button_text" msgid="8119458837558863227">"Izilungiselelo"</string> + <string name="package_state_enqueued" msgid="6227252464303085641">"Ilindile"</string> + <string name="package_state_downloading" msgid="4088770468458724721">"Iyalanda"</string> + <string name="package_state_installing" msgid="7588193972189849870">"Iyafaka"</string> + <string name="package_state_unknown" msgid="7592128424511031410">"Akwaziwa"</string> + <string name="package_state_error" msgid="7672093962724223588">"Ayibuyiselwe"</string> + <string name="abandoned_clean_all" msgid="5256770727689657618">"Susa konke"</string> + <string name="abandoned_clean_this" msgid="7610119707847920412">"Susa"</string> + <string name="abandoned_search" msgid="891119232568284442">"Sesha"</string> + <string name="abandoned_promises_title" msgid="7096178467971716750">"Lolu hlelo lokusebenza alifakiwe"</string> + <string name="abandoned_promise_explanation" msgid="3990027586878167529">"Uhlelo lokusebenza lalesi sithonjana alufakiwe. Ungalisusa, noma sesha uhlelo lokusebenza bese uzifakela lona ngokuzenzela."</string> </resources> diff --git a/res/values/attrs.xml b/res/values/attrs.xml index 0006a7455..65f8f22a6 100644 --- a/res/values/attrs.xml +++ b/res/values/attrs.xml @@ -25,17 +25,8 @@ <attr name="sourceViewId" format="integer" /> </declare-styleable> - <!-- Cling specific attributes. These attributes are used to customize - the cling in XML files. --> - <declare-styleable name="Cling"> - <!-- Used to identify how to draw the cling bg --> - <attr name="drawIdentifier" format="string" /> - </declare-styleable> - - <!-- Page Indicator specific attributes. These attributes are used to customize - the cling in XML files. --> + <!-- Page Indicator specific attributes. --> <declare-styleable name="PageIndicator"> - <!-- Used to identify how to draw the cling bg --> <attr name="windowSize" format="integer" /> </declare-styleable> @@ -98,16 +89,16 @@ <!-- A spacing override for the icons within a page --> <attr name="pageLayoutWidthGap" format="dimension" /> <attr name="pageLayoutHeightGap" format="dimension" /> - <!-- The padding of the pages that are dynamically created per page --> - <attr name="pageLayoutPaddingTop" format="dimension" /> - <attr name="pageLayoutPaddingBottom" format="dimension" /> - <attr name="pageLayoutPaddingLeft" format="dimension" /> - <attr name="pageLayoutPaddingRight" format="dimension" /> <!-- The page indicator for this workspace --> <attr name="pageIndicator" format="reference" /> </declare-styleable> + <declare-styleable name="BubbleTextView"> + <!-- A spacing override for the icons within a page --> + <attr name="customShadows" format="boolean" /> + </declare-styleable> + <!-- AppsCustomizePagedView specific attributes. These attributes are used to customize an AppsCustomizePagedView in xml files. --> <declare-styleable name="AppsCustomizePagedView"> @@ -123,10 +114,6 @@ <attr name="widgetCountX" format="integer" /> <!-- Number of widgets vertically --> <attr name="widgetCountY" format="integer" /> - <!-- The x index of the item to be focused in the cling --> - <attr name="clingFocusedX" format="integer" /> - <!-- The y index of the item to be focused in the cling --> - <attr name="clingFocusedY" format="integer" /> </declare-styleable> <!-- XML attributes used by default_workspace.xml --> @@ -151,9 +138,9 @@ <attr name="workspace" format="reference" /> </declare-styleable> - <!-- Only used in the device overlays --> - <declare-styleable name="CustomClingTitleText"> - </declare-styleable> - <declare-styleable name="CustomClingText"> + <declare-styleable name="PreloadIconDrawable"> + <attr name="background" format="reference" /> + <attr name="ringOutset" format="dimension" /> + <attr name="indicatorSize" format="dimension" /> </declare-styleable> </resources> diff --git a/res/values/colors.xml b/res/values/colors.xml index ffee05f18..29837eaf7 100644 --- a/res/values/colors.xml +++ b/res/values/colors.xml @@ -22,8 +22,10 @@ over the delete target or the info target --> <color name="delete_target_hover_tint">#DAFF0000</color> <color name="info_target_hover_tint">#DA0099CC</color> + <color name="cling_scrim_background">#80000000</color> <color name="bubble_dark_background">#20000000</color> + <color name="focused_background">#80c6c5c5</color> <color name="appwidget_error_color">#FCCC</color> @@ -31,10 +33,9 @@ <color name="workspace_all_apps_and_delete_zone_text_shadow_color">#A0000000</color> <color name="workspace_icon_text_color">#FFF</color> - <color name="apps_customize_icon_text_color">#FFF</color> - <color name="folder_items_text_color">#FF333333</color> - <color name="folder_items_glow_color">#FFCCCCCC</color> + <color name="quantum_panel_text_color">#FF666666</color> + <color name="quantum_panel_text_shadow_color">#FFC4C4C4</color> <color name="outline_color">#FFFFFFFF</color> - - <color name="first_run_cling_circle_background_color">#64b1ea</color> + <color name="widget_text_panel">#FF374248</color> + </resources> diff --git a/res/values/config.xml b/res/values/config.xml index b512ffe67..96bd13bbb 100644 --- a/res/values/config.xml +++ b/res/values/config.xml @@ -17,12 +17,16 @@ <!-- Max number of page indicators to show --> <integer name="config_maxNumberOfPageIndicatorsToShow">21</integer> + <!-- App data backup and restore. To enble backup, register with an android backup service. + http://developer.android.com/guide/topics/data/backup.html#BackupKey --> + <bool name="enable_backup">false</bool> + <!-- DragController --> <integer name="config_flingToDeleteMinVelocity">-1500</integer> <!-- AllApps/Customize/AppsCustomize --> <!-- The alpha of the AppsCustomize bg in spring loaded mode --> - <integer name="config_appsCustomizeSpringLoadedBgAlpha">65</integer> + <integer name="config_workspaceScrimAlpha">55</integer> <integer name="config_workspaceUnshrinkTime">300</integer> <integer name="config_overviewTransitionTime">250</integer> @@ -31,14 +35,20 @@ <!-- Fade/zoom in/out duration & scale in the AllApps transition. Note: This should be less than the workspaceShrinkTime as they happen together. --> + <integer name="config_appsCustomizeRevealTime">220</integer> <integer name="config_appsCustomizeZoomInTime">350</integer> <integer name="config_appsCustomizeZoomOutTime">600</integer> <integer name="config_appsCustomizeZoomScaleFactor">7</integer> <integer name="config_appsCustomizeFadeInTime">250</integer> <integer name="config_appsCustomizeFadeOutTime">200</integer> <integer name="config_appsCustomizeWorkspaceShrinkTime">300</integer> - <integer name="config_appsCustomizeWorkspaceAnimationStagger">40</integer> - <integer name="config_workspaceAppsCustomizeAnimationStagger">100</integer> + + <integer name="config_appsCustomizeConcealTime">250</integer> + <integer name="config_appsCustomizeItemsAlphaStagger">60</integer> + + <!-- This constant stores the ratio of the all apps button drawable which + is used for internal (baked-in) padding --> + <integer name="config_allAppsButtonPaddingPercent">17</integer> <integer name="config_workspaceDefaultScreen">0</integer> @@ -69,7 +79,9 @@ <integer name="config_dropAnimMaxDuration">500</integer> <!-- The duration of the UserFolder opening and closing animation --> - <integer name="config_folderAnimDuration">120</integer> + <integer name="config_folderExpandDuration">120</integer> + <integer name="config_materialFolderExpandDuration">200</integer> + <integer name="config_materialFolderExpandStagger">60</integer> <!-- The distance at which the animation should take the max duration --> <integer name="config_dropAnimMaxDist">800</integer> @@ -81,9 +93,6 @@ <!-- Camera distance for the overscroll effect --> <integer name="config_cameraDistance">8000</integer> - <!-- Whether or not to use custom clings if a custom workspace layout is passed in --> - <bool name="config_useCustomClings">false</bool> - <!-- Hotseat --> <bool name="hotseat_transpose_layout_with_orientation">true</bool> diff --git a/res/values/dimens.xml b/res/values/dimens.xml index 1eca5b382..2c9e689c6 100644 --- a/res/values/dimens.xml +++ b/res/values/dimens.xml @@ -18,8 +18,8 @@ <!-- Dynamic Grid --> <dimen name="dynamic_grid_edge_margin">6dp</dimen> <dimen name="dynamic_grid_search_bar_max_width">500dp</dimen> - <dimen name="dynamic_grid_search_bar_height">48dp</dimen> - <dimen name="dynamic_grid_page_indicator_height">24dp</dimen> + <dimen name="dynamic_grid_search_bar_height">56dp</dimen> + <dimen name="dynamic_grid_page_indicator_height">20dp</dimen> <dimen name="dynamic_grid_icon_drawable_padding">4dp</dimen> <dimen name="dynamic_grid_all_apps_cell_padding">18dp</dimen> <dimen name="dynamic_grid_workspace_page_spacing">8dp</dimen> @@ -29,21 +29,12 @@ <dimen name="dynamic_grid_overview_bar_spacer_width">68dp</dimen> <!-- Cling --> - <dimen name="clingPunchThroughGraphicCenterRadius">94dp</dimen> - <dimen name="folderClingMarginTop">20dp</dimen> - <!-- The offset for the text in the cling --> - <dimen name="cling_text_block_offset_x">0dp</dimen> - <dimen name="cling_text_block_offset_y">0dp</dimen> - <!-- entries for custom clings, will be set in overlays --> - <add-resource type="dimen" name="custom_cling_margin_top" /> - <add-resource type="dimen" name="custom_cling_margin_right" /> - <add-resource type="dimen" name="custom_cling_margin_left" /> - - <dimen name="cling_title_text_size">20sp</dimen> - <dimen name="cling_text_size">14sp</dimen> - <dimen name="cling_alt_title_text_size">24sp</dimen> - <dimen name="cling_alt_text_size">16sp</dimen> - <dimen name="cling_hint_text_size">14sp</dimen> + <dimen name="cling_migration_logo_height">240dp</dimen> + <dimen name="cling_migration_logo_width">165dp</dimen> + <dimen name="cling_migration_bg_size">400dp</dimen> + <dimen name="cling_migration_bg_shift">-200dp</dimen> + <dimen name="cling_migration_content_margin">16dp</dimen> + <dimen name="cling_migration_content_width">280dp</dimen> <!-- Workspace --> <dimen name="workspace_max_gap">16dp</dimen> @@ -62,6 +53,7 @@ <dimen name="apps_customize_tab_bar_height">52dp</dimen> <dimen name="apps_customize_tab_bar_margin_top">0dp</dimen> <dimen name="app_icon_size">48dp</dimen> + <dimen name="apps_customize_horizontal_padding">0dp</dimen> <!-- The AppsCustomize page indicator --> <dimen name="apps_customize_page_indicator_height">12dp</dimen> @@ -88,9 +80,8 @@ <dimen name="app_widget_preview_padding_left">16dp</dimen> <dimen name="app_widget_preview_padding_right">16dp</dimen> <dimen name="app_widget_preview_padding_top">32dp</dimen> - <dimen name="app_widget_preview_label_margin_top">4dp</dimen> - <dimen name="app_widget_preview_label_margin_left">2dp</dimen> - <dimen name="app_widget_preview_label_margin_right">2dp</dimen> + <dimen name="app_widget_preview_label_vertical_padding">8dp</dimen> + <dimen name="app_widget_preview_label_horizontal_padding">8dp</dimen> <!-- Padding applied to shortcut previews --> <dimen name="shortcut_preview_padding_left">0dp</dimen> @@ -101,4 +92,8 @@ <!-- The amount that the preview contents are inset from the preview background --> <dimen name="folder_preview_padding">4dp</dimen> <dimen name="folder_name_padding">10dp</dimen> + +<!-- Sizes for managed profile badges --> + <dimen name="profile_badge_size">24dp</dimen> + <dimen name="profile_badge_margin">4dp</dimen> </resources> diff --git a/res/values/strings.xml b/res/values/strings.xml index 9cb6c293b..ff3509bc5 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -20,6 +20,16 @@ <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <!-- General --> <skip /> + + <!-- URI used to import old favorites. [DO NOT TRANSLATE] --> + <string name="old_launcher_provider_uri" translatable="false">content://com.android.launcher2.settings/favorites?notify=true</string> + + <!-- Permission to receive the com.android.launcher3.action.LAUNCH intent --> + <string name="receive_launch_broadcasts_permission" translatable="false">com.android.launcher3.permission.RECEIVE_LAUNCH_BROADCASTS</string> + + <!-- Permission to receive the com.android.launcher3.action.FIRST_LOAD_COMPLETE intent --> + <string name="receive_first_load_broadcast_permission" translatable="false">com.android.launcher3.permission.RECEIVE_FIRST_LOAD_BROADCAST</string> + <!-- Application name --> <string name="application_name">Launcher3</string> <!-- Accessibility-facing application name --> @@ -30,6 +40,8 @@ <string name="folder_name"></string> <!-- Displayed when user selects a shortcut for an app that was uninstalled [CHAR_LIMIT=none]--> <string name="activity_not_found">App isn\'t installed.</string> + <!-- SafeMode shortcut error string --> + <string name="safemode_shortcut_error">Downloaded app disabled in Safe mode</string> <!-- Labels for the tabs in the customize drawer --> <string name="widgets_tab_label">Widgets</string> @@ -181,6 +193,9 @@ s --> <!-- Text to show user in place of a gadget when we can't display it properly --> <string name="gadget_error_text">Problem loading widget</string> + <!-- Text to show user in place of a gadget when it is not yet initialized. --> + <string name="gadget_setup_text">Setup</string> + <!-- Text to inform the user that they can't uninstall a system application --> <string name="uninstall_system_app_text">This is a system app and can\'t be uninstalled.</string> @@ -228,6 +243,12 @@ s --> <string name="workspace_cling_title">Organize your space</string> <!-- The description of how to use the workspace [CHAR_LIMIT=70] --> <string name="workspace_cling_move_item">Touch & hold background to manage wallpaper, widgets and settings.</string> + <!-- The title text for workspace longpress action [CHAR_LIMIT=40] --> + <string name="workspace_cling_longpress_title">Wallpapers, widgets, & settings</string> + <!-- The description of how to use the workspace [CHAR_LIMIT=70] --> + <string name="workspace_cling_longpress_description">Touch & hold background to customize</string> + <!-- The description of the button to dismiss the cling [CHAR_LIMIT=30] --> + <string name="workspace_cling_longpress_dismiss">GOT IT</string> <!-- The title text for the Folder cling [CHAR_LIMIT=30] --> <string name="folder_cling_title">Here\'s a folder</string> <!-- The description of how to create a folder [CHAR_LIMIT=70] --> @@ -262,4 +283,29 @@ s --> <string name="wallpaper_button_text">Wallpapers</string> <!-- Text for settings button --> <string name="settings_button_text">Settings</string> + + <!-- Label on an icon that references an uninstalled package, that is going to be installed at some point. [CHAR_LIMIT=15] --> + <string name="package_state_enqueued">Waiting</string> + <!-- Label on an icon that references an uninstalled package, that is currently being downloaded. [CHAR_LIMIT=15] --> + <string name="package_state_downloading">Downloading</string> + <!-- Label on an icon that references an uninstalled package, that is currently being installed. [CHAR_LIMIT=15] --> + <string name="package_state_installing">Installing</string> + <!-- Label on an icon that references an uninstalled package, for which we have no information about when it might be installed. [CHAR_LIMIT=15] --> + <string name="package_state_unknown">Unknown</string> + <!-- Label on an icon that references an uninstalled package, for which restore from market has failed. [CHAR_LIMIT=15] --> + <string name="package_state_error">Not restored</string> + + <!-- Button for abandoned promises dialog, that removes all abandoned promise icons. --> + <string name="abandoned_clean_all">Remove All</string> + <!-- Button for abandoned promises dialog, to removes this abandoned promise icon. --> + <string name="abandoned_clean_this">Remove</string> + <!-- Button for abandoned promise dialog, to search in the market for the missing package. --> + <string name="abandoned_search">Search</string> + <!-- Title for abandoned promise dialog. --> + <string name="abandoned_promises_title">This app is not installed</string> + <!-- Explanation for abandoned promise dialog. "The first 'it' refers to the shortcut icon. + The second "it" refers to the app. --> + <string name="abandoned_promise_explanation">The app for this icon isn\'t installed. + You can remove it, or search for the app and install it manually. + </string> </resources> diff --git a/res/values/styles.xml b/res/values/styles.xml index c18dccbab..56a205fd1 100644 --- a/res/values/styles.xml +++ b/res/values/styles.xml @@ -18,53 +18,6 @@ --> <resources> - <style name="ClingButton"> - <item name="android:layout_width">wrap_content</item> - <item name="android:layout_height">wrap_content</item> - <item name="android:paddingTop">15dp</item> - <item name="android:paddingBottom">15dp</item> - <item name="android:paddingLeft">50dp</item> - <item name="android:paddingRight">50dp</item> - <item name="android:text">@string/cling_dismiss</item> - <item name="android:textColor">#ffffff</item> - <item name="android:textStyle">bold</item> - <item name="android:textSize">16sp</item> - <item name="android:background">@drawable/cling_button_bg</item> - </style> - <style name="ClingTitleText"> - <item name="android:layout_width">wrap_content</item> - <item name="android:layout_height">wrap_content</item> - <item name="android:layout_marginBottom">5dp</item> - <item name="android:textSize">@dimen/cling_title_text_size</item> - <item name="android:textColor">#ffffff</item> - <item name="android:fontFamily">sans-serif-condensed</item> - </style> - <style name="ClingText"> - <item name="android:layout_width">wrap_content</item> - <item name="android:layout_height">wrap_content</item> - <item name="android:textSize">@dimen/cling_text_size</item> - <item name="android:textColor">#80000000</item> - <item name="android:lineSpacingMultiplier">1.1</item> - </style> - <style name="ClingAltTitleText"> - <item name="android:layout_width">wrap_content</item> - <item name="android:layout_height">wrap_content</item> - <item name="android:textSize">@dimen/cling_alt_title_text_size</item> - <item name="android:textColor">#49C0EC</item> - </style> - <style name="ClingAltText"> - <item name="android:layout_width">wrap_content</item> - <item name="android:layout_height">wrap_content</item> - <item name="android:textSize">@dimen/cling_alt_text_size</item> - <item name="android:textColor">#49C0EC</item> - </style> - <style name="ClingHintText"> - <item name="android:layout_width">wrap_content</item> - <item name="android:layout_height">wrap_content</item> - <item name="android:textSize">@dimen/cling_hint_text_size</item> - <item name="android:textColor">#80ffffff</item> - <item name="android:fontFamily">sans-serif-condensed</item> - </style> <style name="WorkspaceIcon"> <item name="android:layout_width">match_parent</item> @@ -86,11 +39,19 @@ <style name="WorkspaceIcon.AppsCustomize"> <item name="android:background">@null</item> - <item name="android:textColor">@color/apps_customize_icon_text_color</item> + <item name="android:textColor">@color/quantum_panel_text_color</item> <item name="android:drawablePadding">@dimen/dynamic_grid_icon_drawable_padding</item> - <item name="android:shadowRadius">4.0</item> - <item name="android:shadowColor">#FF000000</item> + <item name="android:shadowRadius">0</item> + <item name="customShadows">false</item> </style> + + <style name="WorkspaceIcon.Folder"> + <item name="android:background">@null</item> + <item name="android:textColor">@color/quantum_panel_text_color</item> + <item name="android:shadowRadius">0</item> + <item name="customShadows">false</item> + </style> + <style name="SearchDropTargetBar"> </style> <style name="SearchButton"> @@ -146,11 +107,19 @@ <item name="android:shadowRadius">2.0</item> </style> - <!-- Overridden in device overlays --> - <style name="CustomClingTitleText"> + <style name="PreloadIcon"> + <item name="background">@drawable/virtual_preload</item> + <item name="indicatorSize">4dp</item> + <item name="ringOutset">4dp</item> </style> - <style name="CustomClingText"> + + <style name="PreloadIcon.Folder"> + <item name="background">@drawable/virtual_preload_folder</item> + <item name="indicatorSize">4dp</item> + <item name="ringOutset">4dp</item> </style> + + <!-- Overridden in device overlays --> <style name="PagedViewWidgetImageView"> <item name="android:paddingLeft">@dimen/app_widget_preview_padding_left</item> </style> diff --git a/res/xml/default_workspace.xml b/res/xml/default_workspace_4x4.xml index 26fc504f0..9bec86aa8 100644 --- a/res/xml/default_workspace.xml +++ b/res/xml/default_workspace_4x4.xml @@ -60,13 +60,21 @@ <!-- Far-right screen [4] --> <!-- Hotseat (We use the screen as the position of the item in the hotseat) --> - <favorite - launcher:packageName="com.android.dialer" - launcher:className="com.android.dialer.DialtactsActivity" + <!-- Dialer, Contacts, [All Apps], Messaging, Browser --> + <resolve launcher:container="-101" launcher:screen="0" launcher:x="0" - launcher:y="0" /> + launcher:y="0" > + <favorite launcher:uri="#Intent;action=android.intent.action.DIAL;end" /> + <favorite launcher:uri="tel:123" /> + <favorite launcher:uri="#Intent;action=android.intent.action.CALL_BUTTON;end" /> + + <favorite + launcher:packageName="com.android.dialer" + launcher:className="com.android.dialer.DialtactsActivity" /> + </resolve> + <favorite launcher:packageName="com.android.contacts" launcher:className="com.android.contacts.activities.PeopleActivity" @@ -74,18 +82,35 @@ launcher:screen="1" launcher:x="1" launcher:y="0" /> - <favorite - launcher:packageName="com.android.mms" - launcher:className="com.android.mms.ui.ConversationList" + + <resolve launcher:container="-101" launcher:screen="3" launcher:x="3" - launcher:y="0" /> - <favorite - launcher:packageName="com.android.browser" - launcher:className="com.android.browser.BrowserActivity" + launcher:y="0" > + <favorite + launcher:uri="#Intent;action=android.intent.action.MAIN;category=android.intent.category.APP_MESSAGING;end" /> + <favorite launcher:uri="sms:" /> + <favorite launcher:uri="smsto:" /> + <favorite launcher:uri="mms:" /> + <favorite launcher:uri="mmsto:" /> + + <favorite + launcher:packageName="com.android.mms" + launcher:className="com.android.mms.ui.ConversationList" /> + </resolve> + <resolve launcher:container="-101" launcher:screen="4" launcher:x="4" - launcher:y="0" /> + launcher:y="0" > + <favorite + launcher:uri="#Intent;action=android.intent.action.MAIN;category=android.intent.category.APP_BROWSER;end" /> + <favorite launcher:uri="http://www.example.com/" /> + + <favorite + launcher:packageName="com.android.browser" + launcher:className="com.android.browser.BrowserActivity" /> + </resolve> + </favorites> diff --git a/res/xml/default_workspace_no_all_apps.xml b/res/xml/default_workspace_4x4_no_all_apps.xml index 7e1301cef..7e1301cef 100644 --- a/res/xml/default_workspace_no_all_apps.xml +++ b/res/xml/default_workspace_4x4_no_all_apps.xml diff --git a/res/xml-sw720dp/default_workspace.xml b/res/xml/default_workspace_5x5.xml index 1c1d70e92..9bec86aa8 100644 --- a/res/xml-sw720dp/default_workspace.xml +++ b/res/xml/default_workspace_5x5.xml @@ -58,4 +58,59 @@ launcher:y="3" /> <!-- Far-right screen [4] --> + + <!-- Hotseat (We use the screen as the position of the item in the hotseat) --> + <!-- Dialer, Contacts, [All Apps], Messaging, Browser --> + <resolve + launcher:container="-101" + launcher:screen="0" + launcher:x="0" + launcher:y="0" > + <favorite launcher:uri="#Intent;action=android.intent.action.DIAL;end" /> + <favorite launcher:uri="tel:123" /> + <favorite launcher:uri="#Intent;action=android.intent.action.CALL_BUTTON;end" /> + + <favorite + launcher:packageName="com.android.dialer" + launcher:className="com.android.dialer.DialtactsActivity" /> + </resolve> + + <favorite + launcher:packageName="com.android.contacts" + launcher:className="com.android.contacts.activities.PeopleActivity" + launcher:container="-101" + launcher:screen="1" + launcher:x="1" + launcher:y="0" /> + + <resolve + launcher:container="-101" + launcher:screen="3" + launcher:x="3" + launcher:y="0" > + <favorite + launcher:uri="#Intent;action=android.intent.action.MAIN;category=android.intent.category.APP_MESSAGING;end" /> + <favorite launcher:uri="sms:" /> + <favorite launcher:uri="smsto:" /> + <favorite launcher:uri="mms:" /> + <favorite launcher:uri="mmsto:" /> + + <favorite + launcher:packageName="com.android.mms" + launcher:className="com.android.mms.ui.ConversationList" /> + </resolve> + <resolve + launcher:container="-101" + launcher:screen="4" + launcher:x="4" + launcher:y="0" > + <favorite + launcher:uri="#Intent;action=android.intent.action.MAIN;category=android.intent.category.APP_BROWSER;end" /> + <favorite launcher:uri="http://www.example.com/" /> + + <favorite + launcher:packageName="com.android.browser" + launcher:className="com.android.browser.BrowserActivity" /> + </resolve> + </favorites> diff --git a/res/xml/default_workspace_5x5_no_all_apps.xml b/res/xml/default_workspace_5x5_no_all_apps.xml new file mode 100644 index 000000000..f54a20425 --- /dev/null +++ b/res/xml/default_workspace_5x5_no_all_apps.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2013 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. +--> + +<favorites xmlns:launcher="http://schemas.android.com/apk/res-auto/com.android.launcher3"> + <!-- Hotseat (We use the screen as the position of the item in the hotseat) --> + <!-- Dialer Hangouts Maps Chrome Camera --> + <favorite + launcher:packageName="com.google.android.dialer" + launcher:className="com.google.android.dialer.extensions.GoogleDialtactsActivity" + launcher:container="-101" + launcher:screen="1" + launcher:x="1" + launcher:y="0" /> + <favorite + launcher:packageName="com.google.android.talk" + launcher:className="com.google.android.talk.SigningInActivity" + launcher:container="-101" + launcher:screen="2" + launcher:x="2" + launcher:y="0" /> + <favorite + launcher:packageName="com.google.android.apps.maps" + launcher:className="com.google.android.maps.MapsActivity" + launcher:container="-101" + launcher:screen="3" + launcher:x="3" + launcher:y="0"/> + <favorite + launcher:packageName="com.android.chrome" + launcher:className="com.google.android.apps.chrome.Main" + launcher:container="-101" + launcher:screen="4" + launcher:x="4" + launcher:y="0" /> + <favorite + launcher:packageName="com.google.android.GoogleCamera" + launcher:className="com.android.camera.CameraLauncher" + launcher:container="-101" + launcher:screen="5" + launcher:x="5" + launcher:y="0" /> +</favorites> + diff --git a/res/xml-sw600dp/default_workspace.xml b/res/xml/default_workspace_5x6.xml index 090c7a7af..d42a93a6a 100644 --- a/res/xml-sw600dp/default_workspace.xml +++ b/res/xml/default_workspace_5x6.xml @@ -60,13 +60,21 @@ <!-- Far-right screen [4] --> <!-- Hotseat (We use the screen as the position of the item in the hotseat) --> - <favorite - launcher:packageName="com.android.dialer" - launcher:className="com.android.dialer.DialtactsActivity" + <!-- Dialer, Contacts, [All Apps], Messaging, Browser --> + <resolve launcher:container="-101" launcher:screen="1" launcher:x="1" - launcher:y="0" /> + launcher:y="0" > + <favorite launcher:uri="#Intent;action=android.intent.action.DIAL;end" /> + <favorite launcher:uri="tel:123" /> + <favorite launcher:uri="#Intent;action=android.intent.action.CALL_BUTTON;end" /> + + <favorite + launcher:packageName="com.android.dialer" + launcher:className="com.android.dialer.DialtactsActivity" /> + </resolve> + <favorite launcher:packageName="com.android.contacts" launcher:className="com.android.contacts.activities.PeopleActivity" @@ -74,18 +82,34 @@ launcher:screen="2" launcher:x="2" launcher:y="0" /> - <favorite - launcher:packageName="com.android.mms" - launcher:className="com.android.mms.ui.ConversationList" + + <resolve launcher:container="-101" launcher:screen="4" launcher:x="4" - launcher:y="0" /> - <favorite - launcher:packageName="com.android.browser" - launcher:className="com.android.browser.BrowserActivity" + launcher:y="0" > + <favorite + launcher:uri="#Intent;action=android.intent.action.MAIN;category=android.intent.category.APP_MESSAGING;end" /> + <favorite launcher:uri="sms:" /> + <favorite launcher:uri="smsto:" /> + <favorite launcher:uri="mms:" /> + <favorite launcher:uri="mmsto:" /> + + <favorite + launcher:packageName="com.android.mms" + launcher:className="com.android.mms.ui.ConversationList" /> + </resolve> + <resolve launcher:container="-101" launcher:screen="5" launcher:x="5" - launcher:y="0" /> + launcher:y="0" > + <favorite + launcher:uri="#Intent;action=android.intent.action.MAIN;category=android.intent.category.APP_BROWSER;end" /> + <favorite launcher:uri="http://www.example.com/" /> + + <favorite + launcher:packageName="com.android.browser" + launcher:className="com.android.browser.BrowserActivity" /> + </resolve> </favorites> diff --git a/res/xml/default_workspace_5x6_no_all_apps.xml b/res/xml/default_workspace_5x6_no_all_apps.xml new file mode 100644 index 000000000..f54a20425 --- /dev/null +++ b/res/xml/default_workspace_5x6_no_all_apps.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2013 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. +--> + +<favorites xmlns:launcher="http://schemas.android.com/apk/res-auto/com.android.launcher3"> + <!-- Hotseat (We use the screen as the position of the item in the hotseat) --> + <!-- Dialer Hangouts Maps Chrome Camera --> + <favorite + launcher:packageName="com.google.android.dialer" + launcher:className="com.google.android.dialer.extensions.GoogleDialtactsActivity" + launcher:container="-101" + launcher:screen="1" + launcher:x="1" + launcher:y="0" /> + <favorite + launcher:packageName="com.google.android.talk" + launcher:className="com.google.android.talk.SigningInActivity" + launcher:container="-101" + launcher:screen="2" + launcher:x="2" + launcher:y="0" /> + <favorite + launcher:packageName="com.google.android.apps.maps" + launcher:className="com.google.android.maps.MapsActivity" + launcher:container="-101" + launcher:screen="3" + launcher:x="3" + launcher:y="0"/> + <favorite + launcher:packageName="com.android.chrome" + launcher:className="com.google.android.apps.chrome.Main" + launcher:container="-101" + launcher:screen="4" + launcher:x="4" + launcher:y="0" /> + <favorite + launcher:packageName="com.google.android.GoogleCamera" + launcher:className="com.android.camera.CameraLauncher" + launcher:container="-101" + launcher:screen="5" + launcher:x="5" + launcher:y="0" /> +</favorites> + diff --git a/src/com/android/launcher3/AddAdapter.java b/src/com/android/launcher3/AddAdapter.java deleted file mode 100644 index 5308a3de4..000000000 --- a/src/com/android/launcher3/AddAdapter.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright (C) 2008 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.content.res.Resources; -import android.graphics.drawable.Drawable; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.BaseAdapter; -import android.widget.TextView; - -import java.util.ArrayList; - -/** - * Adapter showing the types of items that can be added to a {@link Workspace}. - */ -public class AddAdapter extends BaseAdapter { - - private final LayoutInflater mInflater; - - private final ArrayList<ListItem> mItems = new ArrayList<ListItem>(); - - public static final int ITEM_SHORTCUT = 0; - public static final int ITEM_APPWIDGET = 1; - public static final int ITEM_APPLICATION = 2; - public static final int ITEM_WALLPAPER = 3; - - /** - * Specific item in our list. - */ - public class ListItem { - public final CharSequence text; - public final Drawable image; - public final int actionTag; - - public ListItem(Resources res, int textResourceId, int imageResourceId, int actionTag) { - text = res.getString(textResourceId); - if (imageResourceId != -1) { - image = res.getDrawable(imageResourceId); - } else { - image = null; - } - this.actionTag = actionTag; - } - } - - public AddAdapter(Launcher launcher) { - super(); - - mInflater = (LayoutInflater) launcher.getSystemService(Context.LAYOUT_INFLATER_SERVICE); - - // Create default actions - Resources res = launcher.getResources(); - - mItems.add(new ListItem(res, R.string.group_wallpapers, - R.mipmap.ic_launcher_wallpaper, ITEM_WALLPAPER)); - } - - public View getView(int position, View convertView, ViewGroup parent) { - ListItem item = (ListItem) getItem(position); - - if (convertView == null) { - convertView = mInflater.inflate(R.layout.add_list_item, parent, false); - } - - TextView textView = (TextView) convertView; - textView.setTag(item); - textView.setText(item.text); - textView.setCompoundDrawablesWithIntrinsicBounds(item.image, null, null, null); - - return convertView; - } - - public int getCount() { - return mItems.size(); - } - - public Object getItem(int position) { - return mItems.get(position); - } - - public long getItemId(int position) { - return position; - } -} diff --git a/src/com/android/launcher3/AllAppsList.java b/src/com/android/launcher3/AllAppsList.java index 89b291f28..38d2fa541 100644 --- a/src/com/android/launcher3/AllAppsList.java +++ b/src/com/android/launcher3/AllAppsList.java @@ -23,6 +23,10 @@ import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; +import com.android.launcher3.compat.LauncherActivityInfoCompat; +import com.android.launcher3.compat.LauncherAppsCompat; +import com.android.launcher3.compat.UserHandleCompat; + import java.util.ArrayList; import java.util.List; @@ -66,7 +70,7 @@ class AllAppsList { if (mAppFilter != null && !mAppFilter.shouldShowApp(info.componentName)) { return; } - if (findActivity(data, info.componentName)) { + if (findActivity(data, info.componentName, info.user)) { return; } data.add(info); @@ -92,12 +96,14 @@ class AllAppsList { /** * Add the icons for the supplied apk called packageName. */ - public void addPackage(Context context, String packageName) { - final List<ResolveInfo> matches = findActivitiesForPackage(context, packageName); + public void addPackage(Context context, String packageName, UserHandleCompat user) { + final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(context); + final List<LauncherActivityInfoCompat> matches = launcherApps.getActivityList(packageName, + user); if (matches.size() > 0) { - for (ResolveInfo info : matches) { - add(new AppInfo(context.getPackageManager(), info, mIconCache, null)); + for (LauncherActivityInfoCompat info : matches) { + add(new AppInfo(context, info, user, mIconCache, null)); } } } @@ -105,34 +111,37 @@ class AllAppsList { /** * Remove the apps for the given apk identified by packageName. */ - public void removePackage(String packageName) { + public void removePackage(String packageName, UserHandleCompat user) { final List<AppInfo> data = this.data; for (int i = data.size() - 1; i >= 0; i--) { AppInfo info = data.get(i); final ComponentName component = info.intent.getComponent(); - if (packageName.equals(component.getPackageName())) { + if (info.user.equals(user) && packageName.equals(component.getPackageName())) { removed.add(info); data.remove(i); } } - mIconCache.remove(packageName); + mIconCache.remove(packageName, user); } /** * Add and remove icons for this package which has been updated. */ - public void updatePackage(Context context, String packageName) { - final List<ResolveInfo> matches = findActivitiesForPackage(context, packageName); + public void updatePackage(Context context, String packageName, UserHandleCompat user) { + final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(context); + final List<LauncherActivityInfoCompat> matches = launcherApps.getActivityList(packageName, + user); if (matches.size() > 0) { // Find disabled/removed activities and remove them from data and add them // to the removed list. for (int i = data.size() - 1; i >= 0; i--) { final AppInfo applicationInfo = data.get(i); final ComponentName component = applicationInfo.intent.getComponent(); - if (packageName.equals(component.getPackageName())) { + if (user.equals(applicationInfo.user) + && packageName.equals(component.getPackageName())) { if (!findActivity(matches, component)) { removed.add(applicationInfo); - mIconCache.remove(component); + mIconCache.remove(component, user); data.remove(i); } } @@ -142,14 +151,14 @@ class AllAppsList { // Also updates existing activities with new labels/icons int count = matches.size(); for (int i = 0; i < count; i++) { - final ResolveInfo info = matches.get(i); + final LauncherActivityInfoCompat info = matches.get(i); AppInfo applicationInfo = findApplicationInfoLocked( - info.activityInfo.applicationInfo.packageName, - info.activityInfo.name); + info.getComponentName().getPackageName(), user, + info.getComponentName().getClassName()); if (applicationInfo == null) { - add(new AppInfo(context.getPackageManager(), info, mIconCache, null)); + add(new AppInfo(context, info, user, mIconCache, null)); } else { - mIconCache.remove(applicationInfo.componentName); + mIconCache.remove(applicationInfo.componentName, user); mIconCache.getTitleAndIcon(applicationInfo, info, null); modified.add(applicationInfo); } @@ -159,37 +168,24 @@ class AllAppsList { for (int i = data.size() - 1; i >= 0; i--) { final AppInfo applicationInfo = data.get(i); final ComponentName component = applicationInfo.intent.getComponent(); - if (packageName.equals(component.getPackageName())) { + if (user.equals(applicationInfo.user) + && packageName.equals(component.getPackageName())) { removed.add(applicationInfo); - mIconCache.remove(component); + mIconCache.remove(component, user); data.remove(i); } } } } - /** - * Query the package manager for MAIN/LAUNCHER activities in the supplied package. - */ - static List<ResolveInfo> findActivitiesForPackage(Context context, String packageName) { - final PackageManager packageManager = context.getPackageManager(); - - final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null); - mainIntent.addCategory(Intent.CATEGORY_LAUNCHER); - mainIntent.setPackage(packageName); - - final List<ResolveInfo> apps = packageManager.queryIntentActivities(mainIntent, 0); - return apps != null ? apps : new ArrayList<ResolveInfo>(); - } /** * Returns whether <em>apps</em> contains <em>component</em>. */ - private static boolean findActivity(List<ResolveInfo> apps, ComponentName component) { - final String className = component.getClassName(); - for (ResolveInfo info : apps) { - final ActivityInfo activityInfo = info.activityInfo; - if (activityInfo.name.equals(className)) { + private static boolean findActivity(List<LauncherActivityInfoCompat> apps, + ComponentName component) { + for (LauncherActivityInfoCompat info : apps) { + if (info.getComponentName().equals(component)) { return true; } } @@ -197,13 +193,24 @@ class AllAppsList { } /** + * Query the launcher apps service for whether the supplied package has + * MAIN/LAUNCHER activities in the supplied package. + */ + static boolean packageHasActivities(Context context, String packageName, + UserHandleCompat user) { + final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(context); + return launcherApps.getActivityList(packageName, user).size() > 0; + } + + /** * Returns whether <em>apps</em> contains <em>component</em>. */ - private static boolean findActivity(ArrayList<AppInfo> apps, ComponentName component) { + private static boolean findActivity(ArrayList<AppInfo> apps, ComponentName component, + UserHandleCompat user) { final int N = apps.size(); - for (int i=0; i<N; i++) { + for (int i = 0; i < N; i++) { final AppInfo info = apps.get(i); - if (info.componentName.equals(component)) { + if (info.user.equals(user) && info.componentName.equals(component)) { return true; } } @@ -213,10 +220,11 @@ class AllAppsList { /** * Find an ApplicationInfo object for the given packageName and className. */ - private AppInfo findApplicationInfoLocked(String packageName, String className) { + private AppInfo findApplicationInfoLocked(String packageName, UserHandleCompat user, + String className) { for (AppInfo info: data) { final ComponentName component = info.intent.getComponent(); - if (packageName.equals(component.getPackageName()) + if (user.equals(info.user) && packageName.equals(component.getPackageName()) && className.equals(component.getClassName())) { return info; } diff --git a/src/com/android/launcher3/AppInfo.java b/src/com/android/launcher3/AppInfo.java index da222f11f..bfcad84b3 100644 --- a/src/com/android/launcher3/AppInfo.java +++ b/src/com/android/launcher3/AppInfo.java @@ -17,21 +17,26 @@ package com.android.launcher3; import android.content.ComponentName; +import android.content.Context; import android.content.Intent; import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.ResolveInfo; import android.graphics.Bitmap; import android.util.Log; +import com.android.launcher3.compat.LauncherActivityInfoCompat; +import com.android.launcher3.compat.UserManagerCompat; +import com.android.launcher3.compat.UserHandleCompat; + import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; /** * Represents an app in AllAppsView. */ -class AppInfo extends ItemInfo { +public class AppInfo extends ItemInfo { private static final String TAG = "Launcher3.AppInfo"; /** @@ -60,7 +65,7 @@ class AppInfo extends ItemInfo { itemType = LauncherSettings.BaseLauncherColumns.ITEM_TYPE_SHORTCUT; } - protected Intent getIntent() { + public Intent getIntent() { return intent; } @@ -71,28 +76,25 @@ class AppInfo extends ItemInfo { /** * Must not hold the Context. */ - public AppInfo(PackageManager pm, ResolveInfo info, IconCache iconCache, - HashMap<Object, CharSequence> labelCache) { - final String packageName = info.activityInfo.applicationInfo.packageName; - - this.componentName = new ComponentName(packageName, info.activityInfo.name); + public AppInfo(Context context, LauncherActivityInfoCompat info, UserHandleCompat user, + IconCache iconCache, HashMap<Object, CharSequence> labelCache) { + this.componentName = info.getComponentName(); this.container = ItemInfo.NO_ID; - this.setActivity(componentName, - Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); - - try { - PackageInfo pi = pm.getPackageInfo(packageName, 0); - flags = initFlags(pi); - firstInstallTime = initFirstInstallTime(pi); - } catch (NameNotFoundException e) { - Log.d(TAG, "PackageManager.getApplicationInfo failed for " + packageName); - } + flags = initFlags(info); + firstInstallTime = info.getFirstInstallTime(); iconCache.getTitleAndIcon(this, info, labelCache); + intent = new Intent(Intent.ACTION_MAIN); + intent.addCategory(Intent.CATEGORY_LAUNCHER); + intent.setComponent(info.getComponentName()); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); + long serialNumber = UserManagerCompat.getInstance(context).getSerialNumberForUser(user); + intent.putExtra(EXTRA_PROFILE, serialNumber); + this.user = user; } - public static int initFlags(PackageInfo pi) { - int appFlags = pi.applicationInfo.flags; + private static int initFlags(LauncherActivityInfoCompat info) { + int appFlags = info.getApplicationInfo().flags; int flags = 0; if ((appFlags & android.content.pm.ApplicationInfo.FLAG_SYSTEM) == 0) { flags |= DOWNLOADED_FLAG; @@ -104,10 +106,6 @@ class AppInfo extends ItemInfo { return flags; } - public static long initFirstInstallTime(PackageInfo pi) { - return pi.firstInstallTime; - } - public AppInfo(AppInfo info) { super(info); componentName = info.componentName; @@ -115,21 +113,7 @@ class AppInfo extends ItemInfo { intent = new Intent(info.intent); flags = info.flags; firstInstallTime = info.firstInstallTime; - } - - /** - * Creates the application intent based on a component name and various launch flags. - * Sets {@link #itemType} to {@link LauncherSettings.BaseLauncherColumns#ITEM_TYPE_APPLICATION}. - * - * @param className the class name of the component representing the intent - * @param launchFlags the launch flags - */ - final void setActivity(ComponentName className, int launchFlags) { - intent = new Intent(Intent.ACTION_MAIN); - intent.addCategory(Intent.CATEGORY_LAUNCHER); - intent.setComponent(className); - intent.setFlags(launchFlags); - itemType = LauncherSettings.BaseLauncherColumns.ITEM_TYPE_APPLICATION; + iconBitmap = info.iconBitmap; } @Override @@ -137,7 +121,8 @@ class AppInfo extends ItemInfo { return "ApplicationInfo(title=" + title.toString() + " id=" + this.id + " type=" + this.itemType + " container=" + this.container + " screen=" + screenId + " cellX=" + cellX + " cellY=" + cellY - + " spanX=" + spanX + " spanY=" + spanY + " dropPos=" + dropPos + ")"; + + " spanX=" + spanX + " spanY=" + spanY + " dropPos=" + Arrays.toString(dropPos) + + " user=" + user + ")"; } public static void dumpApplicationInfoList(String tag, String label, ArrayList<AppInfo> list) { diff --git a/src/com/android/launcher3/AppWidgetsRestoredReceiver.java b/src/com/android/launcher3/AppWidgetsRestoredReceiver.java new file mode 100644 index 000000000..880aaf1ec --- /dev/null +++ b/src/com/android/launcher3/AppWidgetsRestoredReceiver.java @@ -0,0 +1,94 @@ +package com.android.launcher3; + +import android.appwidget.AppWidgetHost; +import android.appwidget.AppWidgetManager; +import android.appwidget.AppWidgetProviderInfo; +import android.content.BroadcastReceiver; +import android.content.ContentResolver; +import android.content.ContentValues; +import android.content.Context; +import android.content.Intent; +import android.database.Cursor; +import android.os.AsyncTask; +import android.util.Log; + +import com.android.launcher3.LauncherSettings.Favorites; + +import java.util.ArrayList; +import java.util.List; + +public class AppWidgetsRestoredReceiver extends BroadcastReceiver { + + private static final String TAG = "AppWidgetsRestoredReceiver"; + + @Override + public void onReceive(Context context, Intent intent) { + if (AppWidgetManager.ACTION_APPWIDGET_HOST_RESTORED.equals(intent.getAction())) { + int[] oldIds = intent.getIntArrayExtra(AppWidgetManager.EXTRA_APPWIDGET_OLD_IDS); + int[] newIds = intent.getIntArrayExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS); + if (oldIds.length == newIds.length) { + restoreAppWidgetIds(context, oldIds, newIds); + } else { + Log.e(TAG, "Invalid host restored received"); + } + } + } + + /** + * Updates the app widgets whose id has changed during the restore process. + */ + static void restoreAppWidgetIds(Context context, int[] oldWidgetIds, int[] newWidgetIds) { + final ContentResolver cr = context.getContentResolver(); + final List<Integer> idsToRemove = new ArrayList<Integer>(); + final AppWidgetManager widgets = AppWidgetManager.getInstance(context); + + for (int i = 0; i < oldWidgetIds.length; i++) { + Log.i(TAG, "Widget state restore id " + oldWidgetIds[i] + " => " + newWidgetIds[i]); + + final AppWidgetProviderInfo provider = widgets.getAppWidgetInfo(newWidgetIds[i]); + final int state; + if (LauncherModel.isValidProvider(provider)) { + state = LauncherAppWidgetInfo.RESTORE_COMPLETED; + } else { + state = LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY; + } + + ContentValues values = new ContentValues(); + values.put(LauncherSettings.Favorites.APPWIDGET_ID, newWidgetIds[i]); + values.put(LauncherSettings.Favorites.RESTORED, state); + + String[] widgetIdParams = new String[] { Integer.toString(oldWidgetIds[i]) }; + + int result = cr.update(Favorites.CONTENT_URI, values, + "appWidgetId=? and (restored & 1) = 1", widgetIdParams); + if (result == 0) { + Cursor cursor = cr.query(Favorites.CONTENT_URI, + new String[] {Favorites.APPWIDGET_ID}, + "appWidgetId=?", widgetIdParams, null); + try { + if (!cursor.moveToFirst()) { + // The widget no long exists. + idsToRemove.add(newWidgetIds[i]); + } + } finally { + cursor.close(); + } + } + } + // Unregister the widget IDs which are not present on the workspace. This could happen + // when a widget place holder is removed from workspace, before this method is called. + if (!idsToRemove.isEmpty()) { + final AppWidgetHost appWidgetHost = + new AppWidgetHost(context, Launcher.APPWIDGET_HOST_ID); + new AsyncTask<Void, Void, Void>() { + public Void doInBackground(Void ... args) { + for (Integer id : idsToRemove) { + appWidgetHost.deleteAppWidgetId(id); + Log.e(TAG, "Widget no longer present, appWidgetId=" + id); + } + return null; + } + }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void) null); + } + } +} diff --git a/src/com/android/launcher3/AppsCustomizeCellLayout.java b/src/com/android/launcher3/AppsCustomizeCellLayout.java index 3c8bda9db..a50fb6821 100644 --- a/src/com/android/launcher3/AppsCustomizeCellLayout.java +++ b/src/com/android/launcher3/AppsCustomizeCellLayout.java @@ -20,8 +20,16 @@ import android.content.Context; import android.view.View; public class AppsCustomizeCellLayout extends CellLayout implements Page { + + final FocusIndicatorView mFocusHandlerView; + public AppsCustomizeCellLayout(Context context) { super(context); + + mFocusHandlerView = new FocusIndicatorView(context); + addView(mFocusHandlerView, 0); + mFocusHandlerView.getLayoutParams().width = FocusIndicatorView.DEFAULT_LAYOUT_SIZE; + mFocusHandlerView.getLayoutParams().height = FocusIndicatorView.DEFAULT_LAYOUT_SIZE; } @Override @@ -60,4 +68,4 @@ public class AppsCustomizeCellLayout extends CellLayout implements Page { children.getChildAt(j).setOnKeyListener(null); } } -}
\ No newline at end of file +} diff --git a/src/com/android/launcher3/AppsCustomizePagedView.java b/src/com/android/launcher3/AppsCustomizePagedView.java index 251ae2108..1bd290777 100644 --- a/src/com/android/launcher3/AppsCustomizePagedView.java +++ b/src/com/android/launcher3/AppsCustomizePagedView.java @@ -28,7 +28,6 @@ import android.content.pm.ResolveInfo; import android.content.res.Resources; import android.content.res.TypedArray; import android.graphics.Bitmap; -import android.graphics.Canvas; import android.graphics.Point; import android.graphics.Rect; import android.graphics.drawable.Drawable; @@ -44,12 +43,12 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.animation.AccelerateInterpolator; -import android.view.animation.DecelerateInterpolator; import android.widget.GridLayout; import android.widget.ImageView; import android.widget.Toast; import com.android.launcher3.DropTarget.DragObject; +import com.android.launcher3.compat.AppWidgetManagerCompat; import java.util.ArrayList; import java.util.Collections; @@ -144,10 +143,11 @@ class AppsCustomizeAsyncTask extends AsyncTask<AsyncTaskPageData, Void, AsyncTas */ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implements View.OnClickListener, View.OnKeyListener, DragSource, - PagedViewIcon.PressedCallback, PagedViewWidget.ShortPressListener, - LauncherTransitionable { + PagedViewWidget.ShortPressListener, LauncherTransitionable { static final String TAG = "AppsCustomizePagedView"; + private static Rect sTmpRect = new Rect(); + /** * The different content types that this paged view can show. */ @@ -165,40 +165,22 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen // Save and Restore private int mSaveInstanceStateItemIndex = -1; - private PagedViewIcon mPressedIcon; // Content private ArrayList<AppInfo> mApps; private ArrayList<Object> mWidgets; - // Cling - private boolean mHasShownAllAppsCling; - private int mClingFocusedX; - private int mClingFocusedY; - // Caching - private Canvas mCanvas; private IconCache mIconCache; // Dimens private int mContentWidth, mContentHeight; private int mWidgetCountX, mWidgetCountY; - private int mWidgetWidthGap, mWidgetHeightGap; private PagedViewCellLayout mWidgetSpacingLayout; private int mNumAppsPages; private int mNumWidgetPages; private Rect mAllAppsPadding = new Rect(); - // Relating to the scroll and overscroll effects - Workspace.ZInterpolator mZInterpolator = new Workspace.ZInterpolator(0.5f); - private static float CAMERA_DISTANCE = 6500; - private static float TRANSITION_SCALE_FACTOR = 0.74f; - private static float TRANSITION_PIVOT = 0.65f; - private static float TRANSITION_MAX_ROTATION = 22; - private static final boolean PERFORM_OVERSCROLL_ROTATION = true; - private AccelerateInterpolator mAlphaInterpolator = new AccelerateInterpolator(0.9f); - private DecelerateInterpolator mLeftScreenAlphaInterpolator = new DecelerateInterpolator(4); - // Previews & outlines ArrayList<AppsCustomizeAsyncTask> mRunningTasks; private static final int sPageSleepDelay = 200; @@ -213,6 +195,7 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen int mWidgetLoadingId = -1; PendingAddWidgetInfo mCreateWidgetInfo = null; private boolean mDraggingWidget = false; + boolean mPageBackgroundsVisible = true; private Toast mWidgetInstructionToast; @@ -223,19 +206,6 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen private ArrayList<Runnable> mDeferredPrepareLoadWidgetPreviewsTasks = new ArrayList<Runnable>(); - private Rect mTmpRect = new Rect(); - - // Used for drawing shortcut previews - BitmapCache mCachedShortcutPreviewBitmap = new BitmapCache(); - PaintCache mCachedShortcutPreviewPaint = new PaintCache(); - CanvasCache mCachedShortcutPreviewCanvas = new CanvasCache(); - - // Used for drawing widget previews - CanvasCache mCachedAppWidgetPreviewCanvas = new CanvasCache(); - RectCache mCachedAppWidgetPreviewSrcRect = new RectCache(); - RectCache mCachedAppWidgetPreviewDestRect = new RectCache(); - PaintCache mCachedAppWidgetPreviewPaint = new PaintCache(); - WidgetPreviewLoader mWidgetPreviewLoader; private boolean mInBulkBind; @@ -248,18 +218,12 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen mApps = new ArrayList<AppInfo>(); mWidgets = new ArrayList<Object>(); mIconCache = (LauncherAppState.getInstance()).getIconCache(); - mCanvas = new Canvas(); mRunningTasks = new ArrayList<AppsCustomizeAsyncTask>(); // Save the default widget preview background TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.AppsCustomizePagedView, 0, 0); - LauncherAppState app = LauncherAppState.getInstance(); - DeviceProfile grid = app.getDynamicGrid().getDeviceProfile(); - mWidgetWidthGap = mWidgetHeightGap = grid.edgeMarginPx; mWidgetCountX = a.getInt(R.styleable.AppsCustomizePagedView_widgetCountX, 2); mWidgetCountY = a.getInt(R.styleable.AppsCustomizePagedView_widgetCountY, 2); - mClingFocusedX = a.getInt(R.styleable.AppsCustomizePagedView_clingFocusedX, 0); - mClingFocusedY = a.getInt(R.styleable.AppsCustomizePagedView_clingFocusedY, 0); a.recycle(); mWidgetSpacingLayout = new PagedViewCellLayout(getContext()); @@ -271,6 +235,7 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen if (getImportantForAccessibility() == View.IMPORTANT_FOR_ACCESSIBILITY_AUTO) { setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES); } + setSinglePageInViewport(); } @Override @@ -295,8 +260,9 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen void setAllAppsPadding(Rect r) { mAllAppsPadding.set(r); } + void setWidgetsPageIndicatorPadding(int pageIndicatorHeight) { - mPageLayoutPaddingBottom = pageIndicatorHeight; + setPadding(getPaddingLeft(), getPaddingTop(), getPaddingRight(), pageIndicatorHeight); } WidgetPreviewLoader getWidgetPreviewLoader() { @@ -375,8 +341,6 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen // use for each page LauncherAppState app = LauncherAppState.getInstance(); DeviceProfile grid = app.getDynamicGrid().getDeviceProfile(); - mWidgetSpacingLayout.setPadding(mPageLayoutPaddingLeft, mPageLayoutPaddingTop, - mPageLayoutPaddingRight, mPageLayoutPaddingBottom); mCellCountX = (int) grid.allAppsNumCols; mCellCountY = (int) grid.allAppsNumRows; updatePageCounts(); @@ -388,54 +352,32 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen int heightSpec = MeasureSpec.makeMeasureSpec(mContentHeight, MeasureSpec.AT_MOST); mWidgetSpacingLayout.measure(widthSpec, heightSpec); - AppsCustomizeTabHost host = (AppsCustomizeTabHost) getTabHost(); - final boolean hostIsTransitioning = host.isTransitioning(); - - // Restore the page + final boolean hostIsTransitioning = getTabHost().isInTransition(); int page = getPageForComponent(mSaveInstanceStateItemIndex); invalidatePageData(Math.max(0, page), hostIsTransitioning); - - // Show All Apps cling if we are finished transitioning, otherwise, we will try again when - // the transition completes in AppsCustomizeTabHost (otherwise the wrong offsets will be - // returned while animating) - if (!hostIsTransitioning) { - post(new Runnable() { - @Override - public void run() { - showAllAppsCling(); - } - }); - } } - void showAllAppsCling() { - if (!mHasShownAllAppsCling && isDataReady()) { - mHasShownAllAppsCling = true; - // Calculate the position for the cling punch through - int[] offset = new int[2]; - int[] pos = mWidgetSpacingLayout.estimateCellPosition(mClingFocusedX, mClingFocusedY); - mLauncher.getDragLayer().getLocationInDragLayer(this, offset); - // PagedViews are centered horizontally but top aligned - // Note we have to shift the items up now that Launcher sits under the status bar - pos[0] += (getMeasuredWidth() - mWidgetSpacingLayout.getMeasuredWidth()) / 2 + - offset[0]; - pos[1] += offset[1] - mLauncher.getDragLayer().getPaddingTop(); - } - } + protected void onLayout(boolean changed, int l, int t, int r, int b) { + super.onLayout(changed, l, t, r, b); - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - int width = MeasureSpec.getSize(widthMeasureSpec); - int height = MeasureSpec.getSize(heightMeasureSpec); if (!isDataReady()) { if ((LauncherAppState.isDisableAllApps() || !mApps.isEmpty()) && !mWidgets.isEmpty()) { - setDataIsReady(); - setMeasuredDimension(width, height); - onDataReady(width, height); + post(new Runnable() { + // This code triggers requestLayout so must be posted outside of the + // layout pass. + public void run() { + boolean attached = true; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + attached = isAttachedToWindow(); + } + if (attached) { + setDataIsReady(); + onDataReady(getMeasuredWidth(), getMeasuredHeight()); + } + } + }); } } - - super.onMeasure(widthMeasureSpec, heightMeasureSpec); } public void onPackagesUpdated(ArrayList<Object> widgetsAndShortcuts) { @@ -450,7 +392,6 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen if (!app.shouldShowAppOrWidgetProvider(widget.provider)) { continue; } - widget.label = widget.label.trim(); if (widget.minWidth > 0 && widget.minHeight > 0) { // Ensure that all widgets we show can be added on a workspace of this size int[] spanXY = Launcher.getSpanForWidget(mLauncher, widget); @@ -500,40 +441,29 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen @Override public void onClick(View v) { // When we have exited all apps or are in transition, disregard clicks - if (!mLauncher.isAllAppsVisible() || - mLauncher.getWorkspace().isSwitchingState()) return; - - if (v instanceof PagedViewIcon) { - // Animate some feedback to the click - final AppInfo appInfo = (AppInfo) v.getTag(); + if (!mLauncher.isAllAppsVisible() + || mLauncher.getWorkspace().isSwitchingState() + || !(v instanceof PagedViewWidget)) return; - // Lock the drawable state to pressed until we return to Launcher - if (mPressedIcon != null) { - mPressedIcon.lockDrawableState(); - } - mLauncher.startActivitySafely(v, appInfo.intent, appInfo); - mLauncher.getStats().recordLaunch(appInfo.intent); - } else if (v instanceof PagedViewWidget) { - // Let the user know that they have to long press to add a widget - if (mWidgetInstructionToast != null) { - mWidgetInstructionToast.cancel(); - } - mWidgetInstructionToast = Toast.makeText(getContext(),R.string.long_press_widget_to_add, - Toast.LENGTH_SHORT); - mWidgetInstructionToast.show(); - - // Create a little animation to show that the widget can move - float offsetY = getResources().getDimensionPixelSize(R.dimen.dragViewOffsetY); - final ImageView p = (ImageView) v.findViewById(R.id.widget_preview); - AnimatorSet bounce = LauncherAnimUtils.createAnimatorSet(); - ValueAnimator tyuAnim = LauncherAnimUtils.ofFloat(p, "translationY", offsetY); - tyuAnim.setDuration(125); - ValueAnimator tydAnim = LauncherAnimUtils.ofFloat(p, "translationY", 0f); - tydAnim.setDuration(100); - bounce.play(tyuAnim).before(tydAnim); - bounce.setInterpolator(new AccelerateInterpolator()); - bounce.start(); + // Let the user know that they have to long press to add a widget + if (mWidgetInstructionToast != null) { + mWidgetInstructionToast.cancel(); } + mWidgetInstructionToast = Toast.makeText(getContext(),R.string.long_press_widget_to_add, + Toast.LENGTH_SHORT); + mWidgetInstructionToast.show(); + + // Create a little animation to show that the widget can move + float offsetY = getResources().getDimensionPixelSize(R.dimen.dragViewOffsetY); + final ImageView p = (ImageView) v.findViewById(R.id.widget_preview); + AnimatorSet bounce = LauncherAnimUtils.createAnimatorSet(); + ValueAnimator tyuAnim = LauncherAnimUtils.ofFloat(p, "translationY", offsetY); + tyuAnim.setDuration(125); + ValueAnimator tydAnim = LauncherAnimUtils.ofFloat(p, "translationY", 0f); + tydAnim.setDuration(100); + bounce.play(tyuAnim).before(tydAnim); + bounce.setInterpolator(new AccelerateInterpolator()); + bounce.start(); } public boolean onKey(View v, int keyCode, KeyEvent event) { @@ -549,30 +479,29 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen } private void beginDraggingApplication(View v) { - mLauncher.getWorkspace().onDragStartedWithItem(v); mLauncher.getWorkspace().beginDragShared(v, this); } - Bundle getDefaultOptionsForWidget(Launcher launcher, PendingAddWidgetInfo info) { + static Bundle getDefaultOptionsForWidget(Launcher launcher, PendingAddWidgetInfo info) { Bundle options = null; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { - AppWidgetResizeFrame.getWidgetSizeRanges(mLauncher, info.spanX, info.spanY, mTmpRect); - Rect padding = AppWidgetHostView.getDefaultPaddingForWidget(mLauncher, + AppWidgetResizeFrame.getWidgetSizeRanges(launcher, info.spanX, info.spanY, sTmpRect); + Rect padding = AppWidgetHostView.getDefaultPaddingForWidget(launcher, info.componentName, null); - float density = getResources().getDisplayMetrics().density; + float density = launcher.getResources().getDisplayMetrics().density; int xPaddingDips = (int) ((padding.left + padding.right) / density); int yPaddingDips = (int) ((padding.top + padding.bottom) / density); options = new Bundle(); options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH, - mTmpRect.left - xPaddingDips); + sTmpRect.left - xPaddingDips); options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT, - mTmpRect.top - yPaddingDips); + sTmpRect.top - yPaddingDips); options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH, - mTmpRect.right - xPaddingDips); + sTmpRect.right - xPaddingDips); options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT, - mTmpRect.bottom - yPaddingDips); + sTmpRect.bottom - yPaddingDips); } return options; } @@ -591,18 +520,9 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen @Override public void run() { mWidgetLoadingId = mLauncher.getAppWidgetHost().allocateAppWidgetId(); - // Options will be null for platforms with JB or lower, so this serves as an - // SDK level check. - if (options == null) { - if (AppWidgetManager.getInstance(mLauncher).bindAppWidgetIdIfAllowed( - mWidgetLoadingId, info.componentName)) { - mWidgetCleanupState = WIDGET_BOUND; - } - } else { - if (AppWidgetManager.getInstance(mLauncher).bindAppWidgetIdIfAllowed( - mWidgetLoadingId, info.componentName, options)) { - mWidgetCleanupState = WIDGET_BOUND; - } + if(AppWidgetManagerCompat.getInstance(mLauncher).bindAppWidgetIdIfAllowed( + mWidgetLoadingId, pInfo, options)) { + mWidgetCleanupState = WIDGET_BOUND; } } }; @@ -730,9 +650,8 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen int[] previewSizeBeforeScale = new int[1]; - preview = getWidgetPreviewLoader().generateWidgetPreview(createWidgetInfo.componentName, - createWidgetInfo.previewImage, createWidgetInfo.icon, spanX, spanY, - maxWidth, maxHeight, null, previewSizeBeforeScale); + preview = getWidgetPreviewLoader().generateWidgetPreview(createWidgetInfo.info, + spanX, spanY, maxWidth, maxHeight, null, previewSizeBeforeScale); // Compare the size of the drag preview to the preview in the AppsCustomize tray int previewWidthInAppsCustomize = Math.min(previewSizeBeforeScale[0], @@ -749,15 +668,7 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen } else { PendingAddShortcutInfo createShortcutInfo = (PendingAddShortcutInfo) v.getTag(); Drawable icon = mIconCache.getFullResIcon(createShortcutInfo.shortcutActivityInfo); - preview = Bitmap.createBitmap(icon.getIntrinsicWidth(), - icon.getIntrinsicHeight(), Bitmap.Config.ARGB_8888); - - mCanvas.setBitmap(preview); - mCanvas.save(); - WidgetPreviewLoader.renderDrawableToBitmap(icon, preview, 0, 0, - icon.getIntrinsicWidth(), icon.getIntrinsicHeight()); - mCanvas.restore(); - mCanvas.setBitmap(null); + preview = Utilities.createIconBitmap(icon, mLauncher); createItemInfo.spanX = createItemInfo.spanY = 1; } @@ -783,7 +694,7 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen protected boolean beginDragging(final View v) { if (!super.beginDragging(v)) return false; - if (v instanceof PagedViewIcon) { + if (v instanceof BubbleTextView) { beginDraggingApplication(v); } else if (v instanceof PagedViewWidget) { if (!beginDraggingWidget(v)) { @@ -798,9 +709,6 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen public void run() { // We don't enter spring-loaded mode if the drag has been cancelled if (mLauncher.getDragController().isDragging()) { - // Reset the alpha on the dragged icon before we drag - resetDrawableState(); - // Go into spring loaded mode (must happen before we startDrag()) mLauncher.enterSpringLoadedDragMode(); } @@ -820,13 +728,8 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen !(target instanceof DeleteDropTarget) && !(target instanceof Folder))) { // Exit spring loaded mode if we have not successfully dropped or have not handled the // drop in Workspace - mLauncher.getWorkspace().removeExtraEmptyScreen(true, new Runnable() { - @Override - public void run() { - mLauncher.exitSpringLoadedDragMode(); - mLauncher.unlockScreenOrientation(false); - } - }); + mLauncher.exitSpringLoadedDragMode(); + mLauncher.unlockScreenOrientation(false); } else { mLauncher.unlockScreenOrientation(false); } @@ -1019,13 +922,28 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen setVisibilityOnChildren(layout, View.GONE); int widthSpec = MeasureSpec.makeMeasureSpec(mContentWidth, MeasureSpec.AT_MOST); int heightSpec = MeasureSpec.makeMeasureSpec(mContentHeight, MeasureSpec.AT_MOST); - layout.setMinimumWidth(getPageContentWidth()); layout.measure(widthSpec, heightSpec); - layout.setPadding(mAllAppsPadding.left, mAllAppsPadding.top, mAllAppsPadding.right, - mAllAppsPadding.bottom); + + Drawable bg = getContext().getResources().getDrawable(R.drawable.quantum_panel); + if (bg != null) { + bg.setAlpha(mPageBackgroundsVisible ? 255: 0); + layout.setBackground(bg); + } + setVisibilityOnChildren(layout, View.VISIBLE); } + public void setPageBackgroundsVisible(boolean visible) { + mPageBackgroundsVisible = visible; + int childCount = getChildCount(); + for (int i = 0; i < childCount; ++i) { + Drawable bg = getChildAt(i).getBackground(); + if (bg != null) { + bg.setAlpha(visible ? 255 : 0); + } + } + } + public void syncAppsPageItems(int page, boolean immediate) { // ensure that we have the right number of items on the pages final boolean isRtl = isLayoutRtl(); @@ -1039,13 +957,14 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen ArrayList<Bitmap> images = new ArrayList<Bitmap>(); for (int i = startIndex; i < endIndex; ++i) { AppInfo info = mApps.get(i); - PagedViewIcon icon = (PagedViewIcon) mLayoutInflater.inflate( + BubbleTextView icon = (BubbleTextView) mLayoutInflater.inflate( R.layout.apps_customize_application, layout, false); - icon.applyFromApplicationInfo(info, true, this); - icon.setOnClickListener(this); + icon.applyFromApplicationInfo(info); + icon.setOnClickListener(mLauncher); icon.setOnLongClickListener(this); icon.setOnTouchListener(this); icon.setOnKeyListener(this); + icon.setOnFocusChangeListener(layout.mFocusHandlerView); int index = i - startIndex; int x = index % mCellCountX; @@ -1168,21 +1087,27 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen // immediately after syncing, we don't have a proper width. int widthSpec = MeasureSpec.makeMeasureSpec(mContentWidth, MeasureSpec.AT_MOST); int heightSpec = MeasureSpec.makeMeasureSpec(mContentHeight, MeasureSpec.AT_MOST); - layout.setMinimumWidth(getPageContentWidth()); + + Drawable bg = getContext().getResources().getDrawable(R.drawable.quantum_panel_dark); + if (bg != null) { + bg.setAlpha(mPageBackgroundsVisible ? 255 : 0); + layout.setBackground(bg); + } layout.measure(widthSpec, heightSpec); } public void syncWidgetPageItems(final int page, final boolean immediate) { int numItemsPerPage = mWidgetCountX * mWidgetCountY; + final PagedViewGridLayout layout = (PagedViewGridLayout) getPageAt(page); + // Calculate the dimensions of each cell we are giving to each widget final ArrayList<Object> items = new ArrayList<Object>(); - int contentWidth = mContentWidth; - final int cellWidth = ((contentWidth - mPageLayoutPaddingLeft - mPageLayoutPaddingRight - - ((mWidgetCountX - 1) * mWidgetWidthGap)) / mWidgetCountX); - int contentHeight = mContentHeight; - final int cellHeight = ((contentHeight - mPageLayoutPaddingTop - mPageLayoutPaddingBottom - - ((mWidgetCountY - 1) * mWidgetHeightGap)) / mWidgetCountY); + int contentWidth = mContentWidth - layout.getPaddingLeft() - layout.getPaddingRight(); + final int cellWidth = contentWidth / mWidgetCountX; + int contentHeight = mContentHeight - layout.getPaddingTop() - layout.getPaddingBottom(); + + final int cellHeight = contentHeight / mWidgetCountY; // Prepare the set of widgets to load previews for in the background int offset = page * numItemsPerPage; @@ -1191,7 +1116,6 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen } // Prepopulate the pages with the other widget info, and fill in the previews later - final PagedViewGridLayout layout = (PagedViewGridLayout) getPageAt(page); layout.setColumnCount(layout.getCellCountX()); for (int i = 0; i < items.size(); ++i) { Object rawInfo = items.get(i); @@ -1232,14 +1156,22 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen // Layout each widget int ix = i % mWidgetCountX; int iy = i / mWidgetCountX; + + if (ix > 0) { + View border = widget.findViewById(R.id.left_border); + border.setVisibility(View.VISIBLE); + } + if (ix < mWidgetCountX - 1) { + View border = widget.findViewById(R.id.right_border); + border.setVisibility(View.VISIBLE); + } + GridLayout.LayoutParams lp = new GridLayout.LayoutParams( GridLayout.spec(iy, GridLayout.START), GridLayout.spec(ix, GridLayout.TOP)); lp.width = cellWidth; lp.height = cellHeight; lp.setGravity(Gravity.TOP | Gravity.START); - if (ix > 0) lp.leftMargin = mWidgetWidthGap; - if (iy > 0) lp.topMargin = mWidgetHeightGap; layout.addView(widget, lp); } @@ -1389,86 +1321,7 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen // In apps customize, we have a scrolling effect which emulates pulling cards off of a stack. @Override protected void screenScrolled(int screenCenter) { - final boolean isRtl = isLayoutRtl(); super.screenScrolled(screenCenter); - - for (int i = 0; i < getChildCount(); i++) { - View v = getPageAt(i); - if (v != null) { - float scrollProgress = getScrollProgress(screenCenter, v, i); - - float interpolatedProgress; - float translationX; - float maxScrollProgress = Math.max(0, scrollProgress); - float minScrollProgress = Math.min(0, scrollProgress); - - if (isRtl) { - translationX = maxScrollProgress * v.getMeasuredWidth(); - interpolatedProgress = mZInterpolator.getInterpolation(Math.abs(maxScrollProgress)); - } else { - translationX = minScrollProgress * v.getMeasuredWidth(); - interpolatedProgress = mZInterpolator.getInterpolation(Math.abs(minScrollProgress)); - } - float scale = (1 - interpolatedProgress) + - interpolatedProgress * TRANSITION_SCALE_FACTOR; - - float alpha; - if (isRtl && (scrollProgress > 0)) { - alpha = mAlphaInterpolator.getInterpolation(1 - Math.abs(maxScrollProgress)); - } else if (!isRtl && (scrollProgress < 0)) { - alpha = mAlphaInterpolator.getInterpolation(1 - Math.abs(scrollProgress)); - } else { - // On large screens we need to fade the page as it nears its leftmost position - alpha = mLeftScreenAlphaInterpolator.getInterpolation(1 - scrollProgress); - } - - v.setCameraDistance(mDensity * CAMERA_DISTANCE); - int pageWidth = v.getMeasuredWidth(); - int pageHeight = v.getMeasuredHeight(); - - if (PERFORM_OVERSCROLL_ROTATION) { - float xPivot = isRtl ? 1f - TRANSITION_PIVOT : TRANSITION_PIVOT; - boolean isOverscrollingFirstPage = isRtl ? scrollProgress > 0 : scrollProgress < 0; - boolean isOverscrollingLastPage = isRtl ? scrollProgress < 0 : scrollProgress > 0; - - if (i == 0 && isOverscrollingFirstPage) { - // Overscroll to the left - v.setPivotX(xPivot * pageWidth); - v.setRotationY(-TRANSITION_MAX_ROTATION * scrollProgress); - scale = 1.0f; - alpha = 1.0f; - // On the first page, we don't want the page to have any lateral motion - translationX = 0; - } else if (i == getChildCount() - 1 && isOverscrollingLastPage) { - // Overscroll to the right - v.setPivotX((1 - xPivot) * pageWidth); - v.setRotationY(-TRANSITION_MAX_ROTATION * scrollProgress); - scale = 1.0f; - alpha = 1.0f; - // On the last page, we don't want the page to have any lateral motion. - translationX = 0; - } else { - v.setPivotY(pageHeight / 2.0f); - v.setPivotX(pageWidth / 2.0f); - v.setRotationY(0f); - } - } - - v.setTranslationX(translationX); - v.setScaleX(scale); - v.setScaleY(scale); - v.setAlpha(alpha); - - // If the view has 0 alpha, we set it to be invisible so as to prevent - // it from accepting touches - if (alpha == 0) { - v.setVisibility(INVISIBLE); - } else if (v.getVisibility() != VISIBLE) { - v.setVisibility(VISIBLE); - } - } - } - enableHwLayersOnVisiblePages(); } @@ -1513,7 +1366,7 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen } protected void overScroll(float amount) { - acceleratedOverScroll(amount); + dampedOverScroll(amount); } /** @@ -1587,7 +1440,8 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen int length = list.size(); for (int i = 0; i < length; ++i) { AppInfo info = list.get(i); - if (info.intent.getComponent().equals(removeComponent)) { + if (info.user.equals(item.user) + && info.intent.getComponent().equals(removeComponent)) { return i; } } @@ -1625,12 +1479,8 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen // If we have reset, then we should not continue to restore the previous state mSaveInstanceStateItemIndex = -1; - AppsCustomizeTabHost tabHost = getTabHost(); - String tag = tabHost.getCurrentTabTag(); - if (tag != null) { - if (!tag.equals(tabHost.getTabTagForContentType(ContentType.Applications))) { - tabHost.setCurrentTabFromContent(ContentType.Applications); - } + if (mContentType != ContentType.Applications) { + setContentType(ContentType.Applications); } if (mCurrentPage != 0) { @@ -1674,23 +1524,6 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen cancelAllTasks(); } - @Override - public void iconPressed(PagedViewIcon icon) { - // Reset the previously pressed icon and store a reference to the pressed icon so that - // we can reset it on return to Launcher (in Launcher.onResume()) - if (mPressedIcon != null) { - mPressedIcon.resetDrawableState(); - } - mPressedIcon = icon; - } - - public void resetDrawableState() { - if (mPressedIcon != null) { - mPressedIcon.resetDrawableState(); - mPressedIcon = null; - } - } - /* * We load an extra page on each side to prevent flashes from scrolling and loading of the * widget previews in the background with the AsyncTasks. diff --git a/src/com/android/launcher3/AppsCustomizeTabHost.java b/src/com/android/launcher3/AppsCustomizeTabHost.java index bb7f045ce..9a516fd41 100644 --- a/src/com/android/launcher3/AppsCustomizeTabHost.java +++ b/src/com/android/launcher3/AppsCustomizeTabHost.java @@ -29,6 +29,7 @@ import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; +import android.view.accessibility.AccessibilityManager; import android.widget.FrameLayout; import android.widget.LinearLayout; import android.widget.TabHost; @@ -37,35 +38,20 @@ import android.widget.TextView; import java.util.ArrayList; -public class AppsCustomizeTabHost extends TabHost implements LauncherTransitionable, - TabHost.OnTabChangeListener, Insettable { +public class AppsCustomizeTabHost extends FrameLayout implements LauncherTransitionable, Insettable { static final String LOG_TAG = "AppsCustomizeTabHost"; private static final String APPS_TAB_TAG = "APPS"; private static final String WIDGETS_TAB_TAG = "WIDGETS"; - private final LayoutInflater mLayoutInflater; - private ViewGroup mTabs; - private ViewGroup mTabsContainer; - private AppsCustomizePagedView mAppsCustomizePane; - private FrameLayout mAnimationBuffer; - private LinearLayout mContent; - - private boolean mInTransition; - private boolean mTransitioningToWorkspace; - private boolean mResetAfterTransition; - private Runnable mRelayoutAndMakeVisible; + private AppsCustomizePagedView mPagedView; + private View mContent; + private boolean mInTransition = false; + private final Rect mInsets = new Rect(); public AppsCustomizeTabHost(Context context, AttributeSet attrs) { super(context, attrs); - mLayoutInflater = LayoutInflater.from(context); - mRelayoutAndMakeVisible = new Runnable() { - public void run() { - mTabs.requestLayout(); - mTabsContainer.setAlpha(1f); - } - }; } /** @@ -75,17 +61,17 @@ public class AppsCustomizeTabHost extends TabHost implements LauncherTransitiona * tabs manually). */ void setContentTypeImmediate(AppsCustomizePagedView.ContentType type) { - setOnTabChangedListener(null); - onTabChangedStart(); - onTabChangedEnd(type); - setCurrentTabByTag(getTabTagForContentType(type)); - setOnTabChangedListener(this); + mPagedView.setContentType(type); + } + + public void setCurrentTabFromContent(AppsCustomizePagedView.ContentType type) { + setContentTypeImmediate(type); } @Override public void setInsets(Rect insets) { mInsets.set(insets); - FrameLayout.LayoutParams flp = (LayoutParams) mContent.getLayoutParams(); + LayoutParams flp = (LayoutParams) mContent.getLayoutParams(); flp.topMargin = insets.top; flp.bottomMargin = insets.bottom; flp.leftMargin = insets.left; @@ -98,212 +84,12 @@ public class AppsCustomizeTabHost extends TabHost implements LauncherTransitiona */ @Override protected void onFinishInflate() { - // Setup the tab host - setup(); - - final ViewGroup tabsContainer = (ViewGroup) findViewById(R.id.tabs_container); - final TabWidget tabs = getTabWidget(); - final AppsCustomizePagedView appsCustomizePane = (AppsCustomizePagedView) - findViewById(R.id.apps_customize_pane_content); - mTabs = tabs; - mTabsContainer = tabsContainer; - mAppsCustomizePane = appsCustomizePane; - mAnimationBuffer = (FrameLayout) findViewById(R.id.animation_buffer); - mContent = (LinearLayout) findViewById(R.id.apps_customize_content); - if (tabs == null || mAppsCustomizePane == null) throw new Resources.NotFoundException(); - - // Configure the tabs content factory to return the same paged view (that we change the - // content filter on) - TabContentFactory contentFactory = new TabContentFactory() { - public View createTabContent(String tag) { - return appsCustomizePane; - } - }; - - // Create the tabs - TextView tabView; - String label; - label = getContext().getString(R.string.all_apps_button_label); - tabView = (TextView) mLayoutInflater.inflate(R.layout.tab_widget_indicator, tabs, false); - tabView.setText(label); - tabView.setContentDescription(label); - addTab(newTabSpec(APPS_TAB_TAG).setIndicator(tabView).setContent(contentFactory)); - label = getContext().getString(R.string.widgets_tab_label); - tabView = (TextView) mLayoutInflater.inflate(R.layout.tab_widget_indicator, tabs, false); - tabView.setText(label); - tabView.setContentDescription(label); - addTab(newTabSpec(WIDGETS_TAB_TAG).setIndicator(tabView).setContent(contentFactory)); - setOnTabChangedListener(this); - - // Setup the key listener to jump between the last tab view and the market icon - AppsCustomizeTabKeyEventListener keyListener = new AppsCustomizeTabKeyEventListener(); - View lastTab = tabs.getChildTabViewAt(tabs.getTabCount() - 1); - lastTab.setOnKeyListener(keyListener); - View shopButton = findViewById(R.id.market_button); - shopButton.setOnKeyListener(keyListener); - - // Hide the tab bar until we measure - mTabsContainer.setAlpha(0f); - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - boolean remeasureTabWidth = (mTabs.getLayoutParams().width <= 0); - super.onMeasure(widthMeasureSpec, heightMeasureSpec); - - // Set the width of the tab list to the content width - if (remeasureTabWidth) { - int contentWidth = mAppsCustomizePane.getPageContentWidth(); - if (contentWidth > 0 && mTabs.getLayoutParams().width != contentWidth) { - // Set the width and show the tab bar - mTabs.getLayoutParams().width = contentWidth; - mRelayoutAndMakeVisible.run(); - } - - super.onMeasure(widthMeasureSpec, heightMeasureSpec); - } - } - - public boolean onInterceptTouchEvent(MotionEvent ev) { - // If we are mid transitioning to the workspace, then intercept touch events here so we - // can ignore them, otherwise we just let all apps handle the touch events. - if (mInTransition && mTransitioningToWorkspace) { - return true; - } - return super.onInterceptTouchEvent(ev); - }; - - @Override - public boolean onTouchEvent(MotionEvent event) { - // Allow touch events to fall through to the workspace if we are transitioning there - if (mInTransition && mTransitioningToWorkspace) { - return super.onTouchEvent(event); - } - - // Intercept all touch events up to the bottom of the AppsCustomizePane so they do not fall - // through to the workspace and trigger showWorkspace() - if (event.getY() < mAppsCustomizePane.getBottom()) { - return true; - } - return super.onTouchEvent(event); - } - - private void onTabChangedStart() { + mPagedView = (AppsCustomizePagedView) findViewById(R.id.apps_customize_pane_content); + mContent = findViewById(R.id.content); } - private void reloadCurrentPage() { - mAppsCustomizePane.loadAssociatedPages(mAppsCustomizePane.getCurrentPage()); - mAppsCustomizePane.requestFocus(); - } - - private void onTabChangedEnd(AppsCustomizePagedView.ContentType type) { - int bgAlpha = (int) (255 * (getResources().getInteger( - R.integer.config_appsCustomizeSpringLoadedBgAlpha) / 100f)); - setBackgroundColor(Color.argb(bgAlpha, 0, 0, 0)); - mAppsCustomizePane.setContentType(type); - } - - @Override - public void onTabChanged(String tabId) { - final AppsCustomizePagedView.ContentType type = getContentTypeForTabTag(tabId); - - // Animate the changing of the tab content by fading pages in and out - final Resources res = getResources(); - final int duration = res.getInteger(R.integer.config_tabTransitionDuration); - - // We post a runnable here because there is a delay while the first page is loading and - // the feedback from having changed the tab almost feels better than having it stick - post(new Runnable() { - @Override - public void run() { - if (mAppsCustomizePane.getMeasuredWidth() <= 0 || - mAppsCustomizePane.getMeasuredHeight() <= 0) { - reloadCurrentPage(); - return; - } - - // Take the visible pages and re-parent them temporarily to mAnimatorBuffer - // and then cross fade to the new pages - int[] visiblePageRange = new int[2]; - mAppsCustomizePane.getVisiblePages(visiblePageRange); - if (visiblePageRange[0] == -1 && visiblePageRange[1] == -1) { - // If we can't get the visible page ranges, then just skip the animation - reloadCurrentPage(); - return; - } - ArrayList<View> visiblePages = new ArrayList<View>(); - for (int i = visiblePageRange[0]; i <= visiblePageRange[1]; i++) { - visiblePages.add(mAppsCustomizePane.getPageAt(i)); - } - - // We want the pages to be rendered in exactly the same way as they were when - // their parent was mAppsCustomizePane -- so set the scroll on mAnimationBuffer - // to be exactly the same as mAppsCustomizePane, and below, set the left/top - // parameters to be correct for each of the pages - mAnimationBuffer.scrollTo(mAppsCustomizePane.getScrollX(), 0); - - // mAppsCustomizePane renders its children in reverse order, so - // add the pages to mAnimationBuffer in reverse order to match that behavior - for (int i = visiblePages.size() - 1; i >= 0; i--) { - View child = visiblePages.get(i); - if (child instanceof AppsCustomizeCellLayout) { - ((AppsCustomizeCellLayout) child).resetChildrenOnKeyListeners(); - } else if (child instanceof PagedViewGridLayout) { - ((PagedViewGridLayout) child).resetChildrenOnKeyListeners(); - } - PagedViewWidget.setDeletePreviewsWhenDetachedFromWindow(false); - mAppsCustomizePane.removeView(child); - PagedViewWidget.setDeletePreviewsWhenDetachedFromWindow(true); - mAnimationBuffer.setAlpha(1f); - mAnimationBuffer.setVisibility(View.VISIBLE); - LayoutParams p = new FrameLayout.LayoutParams(child.getMeasuredWidth(), - child.getMeasuredHeight()); - p.setMargins((int) child.getLeft(), (int) child.getTop(), 0, 0); - mAnimationBuffer.addView(child, p); - } - - // Toggle the new content - onTabChangedStart(); - onTabChangedEnd(type); - - // Animate the transition - ObjectAnimator outAnim = LauncherAnimUtils.ofFloat(mAnimationBuffer, "alpha", 0f); - outAnim.addListener(new AnimatorListenerAdapter() { - private void clearAnimationBuffer() { - mAnimationBuffer.setVisibility(View.GONE); - PagedViewWidget.setRecyclePreviewsWhenDetachedFromWindow(false); - mAnimationBuffer.removeAllViews(); - PagedViewWidget.setRecyclePreviewsWhenDetachedFromWindow(true); - } - @Override - public void onAnimationEnd(Animator animation) { - clearAnimationBuffer(); - } - @Override - public void onAnimationCancel(Animator animation) { - clearAnimationBuffer(); - } - }); - ObjectAnimator inAnim = LauncherAnimUtils.ofFloat(mAppsCustomizePane, "alpha", 1f); - inAnim.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - reloadCurrentPage(); - } - }); - - final AnimatorSet animSet = LauncherAnimUtils.createAnimatorSet(); - animSet.playTogether(outAnim, inAnim); - animSet.setDuration(duration); - animSet.start(); - } - }); - } - - public void setCurrentTabFromContent(AppsCustomizePagedView.ContentType type) { - setOnTabChangedListener(null); - setCurrentTabByTag(getTabTagForContentType(type)); - setOnTabChangedListener(this); + public String getContentTag() { + return getTabTagForContentType(mPagedView.getContentType()); } /** @@ -342,44 +128,41 @@ public class AppsCustomizeTabHost extends TabHost implements LauncherTransitiona } void reset() { - if (mInTransition) { - // Defer to after the transition to reset - mResetAfterTransition = true; - } else { - // Reset immediately - mAppsCustomizePane.reset(); - } + // Reset immediately + mPagedView.reset(); } - private void enableAndBuildHardwareLayer() { - // isHardwareAccelerated() checks if we're attached to a window and if that - // window is HW accelerated-- we were sometimes not attached to a window - // and buildLayer was throwing an IllegalStateException - if (isHardwareAccelerated()) { - // Turn on hardware layers for performance - setLayerType(LAYER_TYPE_HARDWARE, null); - - // force building the layer, so you don't get a blip early in an animation - // when the layer is created layer - buildLayer(); + public void onWindowVisible() { + if (getVisibility() == VISIBLE) { + mContent.setVisibility(VISIBLE); + // We unload the widget previews when the UI is hidden, so need to reload pages + // Load the current page synchronously, and the neighboring pages asynchronously + mPagedView.loadAssociatedPages(mPagedView.getCurrentPage(), true); + mPagedView.loadAssociatedPages(mPagedView.getCurrentPage()); } } + public void onTrimMemory() { + mContent.setVisibility(GONE); + // Clear the widget pages of all their subviews - this will trigger the widget previews + // to delete their bitmaps + mPagedView.clearAllWidgetPages(); + } + @Override - public View getContent() { - View appsCustomizeContent = mAppsCustomizePane.getContent(); - if (appsCustomizeContent != null) { - return appsCustomizeContent; - } - return mContent; + public ViewGroup getContent() { + return mPagedView; + } + + public boolean isInTransition() { + return mInTransition; } /* LauncherTransitionable overrides */ @Override public void onLauncherTransitionPrepare(Launcher l, boolean animated, boolean toWorkspace) { - mAppsCustomizePane.onLauncherTransitionPrepare(l, animated, toWorkspace); + mPagedView.onLauncherTransitionPrepare(l, animated, toWorkspace); mInTransition = true; - mTransitioningToWorkspace = toWorkspace; if (toWorkspace) { // Going from All Apps -> Workspace @@ -390,45 +173,38 @@ public class AppsCustomizeTabHost extends TabHost implements LauncherTransitiona // Make sure the current page is loaded (we start loading the side pages after the // transition to prevent slowing down the animation) - mAppsCustomizePane.loadAssociatedPages(mAppsCustomizePane.getCurrentPage(), true); - } - - if (mResetAfterTransition) { - mAppsCustomizePane.reset(); - mResetAfterTransition = false; + // TODO: revisit this + mPagedView.loadAssociatedPages(mPagedView.getCurrentPage()); } } @Override public void onLauncherTransitionStart(Launcher l, boolean animated, boolean toWorkspace) { - mAppsCustomizePane.onLauncherTransitionStart(l, animated, toWorkspace); - if (animated) { - enableAndBuildHardwareLayer(); - } - - // Dismiss the workspace cling - l.getLauncherClings().dismissWorkspaceCling(null); + mPagedView.onLauncherTransitionStart(l, animated, toWorkspace); } @Override public void onLauncherTransitionStep(Launcher l, float t) { - mAppsCustomizePane.onLauncherTransitionStep(l, t); + mPagedView.onLauncherTransitionStep(l, t); } @Override public void onLauncherTransitionEnd(Launcher l, boolean animated, boolean toWorkspace) { - mAppsCustomizePane.onLauncherTransitionEnd(l, animated, toWorkspace); + mPagedView.onLauncherTransitionEnd(l, animated, toWorkspace); mInTransition = false; - if (animated) { - setLayerType(LAYER_TYPE_NONE, null); - } if (!toWorkspace) { - // Show the all apps cling (if not already shown) - mAppsCustomizePane.showAllAppsCling(); // Make sure adjacent pages are loaded (we wait until after the transition to // prevent slowing down the animation) - mAppsCustomizePane.loadAssociatedPages(mAppsCustomizePane.getCurrentPage()); + mPagedView.loadAssociatedPages(mPagedView.getCurrentPage()); + + // Opening apps, need to announce what page we are on. + AccessibilityManager am = (AccessibilityManager) + getContext().getSystemService(Context.ACCESSIBILITY_SERVICE); + if (am.isEnabled()) { + // Notify the user when the page changes + announceForAccessibility(mPagedView.getCurrentPageDescription()); + } // Going from Workspace -> All Apps // NOTE: We should do this at the end since we check visibility state in some of the @@ -459,25 +235,4 @@ public class AppsCustomizeTabHost extends TabHost implements LauncherTransitiona throw new RuntimeException("Failed; can't get z-order of views"); } } - - public void onWindowVisible() { - if (getVisibility() == VISIBLE) { - mContent.setVisibility(VISIBLE); - // We unload the widget previews when the UI is hidden, so need to reload pages - // Load the current page synchronously, and the neighboring pages asynchronously - mAppsCustomizePane.loadAssociatedPages(mAppsCustomizePane.getCurrentPage(), true); - mAppsCustomizePane.loadAssociatedPages(mAppsCustomizePane.getCurrentPage()); - } - } - - public void onTrimMemory() { - mContent.setVisibility(GONE); - // Clear the widget pages of all their subviews - this will trigger the widget previews - // to delete their bitmaps - mAppsCustomizePane.clearAllWidgetPages(); - } - - boolean isTransitioning() { - return mInTransition; - } } diff --git a/src/com/android/launcher3/AutoInstallsLayout.java b/src/com/android/launcher3/AutoInstallsLayout.java new file mode 100644 index 000000000..00f0cf36f --- /dev/null +++ b/src/com/android/launcher3/AutoInstallsLayout.java @@ -0,0 +1,564 @@ +/* + * Copyright (C) 2014 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.appwidget.AppWidgetHost; +import android.appwidget.AppWidgetManager; +import android.content.ComponentName; +import android.content.ContentValues; +import android.content.Context; +import android.content.Intent; +import android.content.pm.ActivityInfo; +import android.content.pm.PackageManager; +import android.content.res.Resources; +import android.content.res.XmlResourceParser; +import android.database.sqlite.SQLiteDatabase; +import android.graphics.drawable.Drawable; +import android.net.Uri; +import android.os.Bundle; +import android.text.TextUtils; +import android.util.Log; +import android.util.Pair; +import android.util.Patterns; + +import com.android.launcher3.LauncherProvider.SqlArguments; +import com.android.launcher3.LauncherProvider.WorkspaceLoader; +import com.android.launcher3.LauncherSettings.Favorites; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; + +/** + * This class contains contains duplication of functionality as found in + * LauncherProvider#DatabaseHelper. It has been isolated and differentiated in order + * to cleanly and separately represent AutoInstall default layout format and policy. + */ +public class AutoInstallsLayout implements WorkspaceLoader { + private static final String TAG = "AutoInstalls"; + private static final boolean LOGD = true; + + /** Marker action used to discover a package which defines launcher customization */ + static final String ACTION_LAUNCHER_CUSTOMIZATION = + "android.autoinstalls.config.action.PLAY_AUTO_INSTALL"; + + private static final String LAYOUT_RES = "default_layout"; + + static AutoInstallsLayout get(Context context, AppWidgetHost appWidgetHost, + LayoutParserCallback callback) { + Pair<String, Resources> customizationApkInfo = Utilities.findSystemApk( + ACTION_LAUNCHER_CUSTOMIZATION, context.getPackageManager()); + if (customizationApkInfo == null) { + return null; + } + + String pkg = customizationApkInfo.first; + Resources res = customizationApkInfo.second; + int layoutId = res.getIdentifier(LAYOUT_RES, "xml", pkg); + if (layoutId == 0) { + Log.e(TAG, "Layout definition not found in package: " + pkg); + return null; + } + return new AutoInstallsLayout(context, appWidgetHost, callback, pkg, res, layoutId); + } + + // Object Tags + private static final String TAG_WORKSPACE = "workspace"; + private static final String TAG_APP_ICON = "appicon"; + private static final String TAG_AUTO_INSTALL = "autoinstall"; + private static final String TAG_FOLDER = "folder"; + private static final String TAG_APPWIDGET = "appwidget"; + private static final String TAG_SHORTCUT = "shortcut"; + private static final String TAG_EXTRA = "extra"; + + private static final String ATTR_CONTAINER = "container"; + private static final String ATTR_RANK = "rank"; + + private static final String ATTR_PACKAGE_NAME = "packageName"; + private static final String ATTR_CLASS_NAME = "className"; + private static final String ATTR_TITLE = "title"; + private static final String ATTR_SCREEN = "screen"; + private static final String ATTR_X = "x"; + private static final String ATTR_Y = "y"; + private static final String ATTR_SPAN_X = "spanX"; + private static final String ATTR_SPAN_Y = "spanY"; + private static final String ATTR_ICON = "icon"; + private static final String ATTR_URL = "url"; + + // Style attrs -- "Extra" + private static final String ATTR_KEY = "key"; + private static final String ATTR_VALUE = "value"; + + private static final String HOTSEAT_CONTAINER_NAME = + Favorites.containerToString(Favorites.CONTAINER_HOTSEAT); + + private static final String ACTION_APPWIDGET_DEFAULT_WORKSPACE_CONFIGURE = + "com.android.launcher.action.APPWIDGET_DEFAULT_WORKSPACE_CONFIGURE"; + + private final Context mContext; + private final AppWidgetHost mAppWidgetHost; + private final LayoutParserCallback mCallback; + + private final PackageManager mPackageManager; + private final ContentValues mValues; + + private final Resources mRes; + private final int mLayoutId; + + private SQLiteDatabase mDb; + + public AutoInstallsLayout(Context context, AppWidgetHost appWidgetHost, + LayoutParserCallback callback, String packageName, Resources res, int layoutId) { + mContext = context; + mAppWidgetHost = appWidgetHost; + mCallback = callback; + + mPackageManager = context.getPackageManager(); + mValues = new ContentValues(); + + mRes = res; + mLayoutId = layoutId; + } + + @Override + public int loadLayout(SQLiteDatabase db, ArrayList<Long> screenIds) { + mDb = db; + try { + return parseLayout(mRes, mLayoutId, screenIds); + } catch (XmlPullParserException | IOException | RuntimeException e) { + Log.w(TAG, "Got exception parsing layout.", e); + return -1; + } + } + + private int parseLayout(Resources res, int layoutId, ArrayList<Long> screenIds) + throws XmlPullParserException, IOException { + final int hotseatAllAppsRank = LauncherAppState.getInstance() + .getDynamicGrid().getDeviceProfile().hotseatAllAppsRank; + + XmlResourceParser parser = res.getXml(layoutId); + beginDocument(parser, TAG_WORKSPACE); + final int depth = parser.getDepth(); + int type; + HashMap<String, TagParser> tagParserMap = getLayoutElementsMap(); + int count = 0; + + while (((type = parser.next()) != XmlPullParser.END_TAG || + parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) { + if (type != XmlPullParser.START_TAG) { + continue; + } + + mValues.clear(); + final int container; + final long screenId; + + if (HOTSEAT_CONTAINER_NAME.equals(getAttributeValue(parser, ATTR_CONTAINER))) { + container = Favorites.CONTAINER_HOTSEAT; + + // Hack: hotseat items are stored using screen ids + long rank = Long.parseLong(getAttributeValue(parser, ATTR_RANK)); + screenId = (rank < hotseatAllAppsRank) ? rank : (rank + 1); + + } else { + container = Favorites.CONTAINER_DESKTOP; + screenId = Long.parseLong(getAttributeValue(parser, ATTR_SCREEN)); + + mValues.put(Favorites.CELLX, getAttributeValue(parser, ATTR_X)); + mValues.put(Favorites.CELLY, getAttributeValue(parser, ATTR_Y)); + } + + mValues.put(Favorites.CONTAINER, container); + mValues.put(Favorites.SCREEN, screenId); + + TagParser tagParser = tagParserMap.get(parser.getName()); + if (tagParser == null) { + if (LOGD) Log.d(TAG, "Ignoring unknown element tag: " + parser.getName()); + continue; + } + long newElementId = tagParser.parseAndAdd(parser, res); + if (newElementId >= 0) { + // Keep track of the set of screens which need to be added to the db. + if (!screenIds.contains(screenId) && + container == Favorites.CONTAINER_DESKTOP) { + screenIds.add(screenId); + } + count++; + } + } + return count; + } + + protected long addShortcut(String title, Intent intent, int type) { + long id = mCallback.generateNewItemId(); + mValues.put(Favorites.INTENT, intent.toUri(0)); + mValues.put(Favorites.TITLE, title); + mValues.put(Favorites.ITEM_TYPE, type); + mValues.put(Favorites.SPANX, 1); + mValues.put(Favorites.SPANY, 1); + mValues.put(Favorites._ID, id); + if (mCallback.insertAndCheck(mDb, mValues) < 0) { + return -1; + } else { + return id; + } + } + + protected HashMap<String, TagParser> getFolderElementsMap() { + HashMap<String, TagParser> parsers = new HashMap<String, TagParser>(); + parsers.put(TAG_APP_ICON, new AppShortcutParser()); + parsers.put(TAG_AUTO_INSTALL, new AutoInstallParser()); + parsers.put(TAG_SHORTCUT, new ShortcutParser()); + return parsers; + } + + protected HashMap<String, TagParser> getLayoutElementsMap() { + HashMap<String, TagParser> parsers = new HashMap<String, TagParser>(); + parsers.put(TAG_APP_ICON, new AppShortcutParser()); + parsers.put(TAG_AUTO_INSTALL, new AutoInstallParser()); + parsers.put(TAG_FOLDER, new FolderParser()); + parsers.put(TAG_APPWIDGET, new AppWidgetParser()); + parsers.put(TAG_SHORTCUT, new ShortcutParser()); + return parsers; + } + + private interface TagParser { + /** + * Parses the tag and adds to the db + * @return the id of the row added or -1; + */ + long parseAndAdd(XmlResourceParser parser, Resources res) + throws XmlPullParserException, IOException; + } + + private class AppShortcutParser implements TagParser { + + @Override + public long parseAndAdd(XmlResourceParser parser, Resources res) { + final String packageName = getAttributeValue(parser, ATTR_PACKAGE_NAME); + final String className = getAttributeValue(parser, ATTR_CLASS_NAME); + + if (!TextUtils.isEmpty(packageName) && !TextUtils.isEmpty(className)) { + ActivityInfo info; + try { + ComponentName cn; + try { + cn = new ComponentName(packageName, className); + info = mPackageManager.getActivityInfo(cn, 0); + } catch (PackageManager.NameNotFoundException nnfe) { + String[] packages = mPackageManager.currentToCanonicalPackageNames( + new String[] { packageName }); + cn = new ComponentName(packages[0], className); + info = mPackageManager.getActivityInfo(cn, 0); + } + final Intent intent = new Intent(Intent.ACTION_MAIN, null) + .addCategory(Intent.CATEGORY_LAUNCHER) + .setComponent(cn) + .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | + Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); + + return addShortcut(info.loadLabel(mPackageManager).toString(), + intent, Favorites.ITEM_TYPE_APPLICATION); + } catch (PackageManager.NameNotFoundException e) { + Log.w(TAG, "Unable to add favorite: " + packageName + "/" + className, e); + } + return -1; + } else { + if (LOGD) Log.d(TAG, "Skipping invalid <favorite> with no component or uri"); + return -1; + } + } + } + + private class AutoInstallParser implements TagParser { + + @Override + public long parseAndAdd(XmlResourceParser parser, Resources res) { + final String packageName = getAttributeValue(parser, ATTR_PACKAGE_NAME); + final String className = getAttributeValue(parser, ATTR_CLASS_NAME); + if (TextUtils.isEmpty(packageName) || TextUtils.isEmpty(className)) { + if (LOGD) Log.d(TAG, "Skipping invalid <favorite> with no component"); + return -1; + } + + mValues.put(Favorites.RESTORED, ShortcutInfo.FLAG_AUTOINTALL_ICON); + final Intent intent = new Intent(Intent.ACTION_MAIN, null) + .addCategory(Intent.CATEGORY_LAUNCHER) + .setComponent(new ComponentName(packageName, className)) + .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | + Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); + return addShortcut(mContext.getString(R.string.package_state_unknown), intent, + Favorites.ITEM_TYPE_APPLICATION); + } + } + + private class ShortcutParser implements TagParser { + + @Override + public long parseAndAdd(XmlResourceParser parser, Resources res) { + final String url = getAttributeValue(parser, ATTR_URL); + final int titleResId = getAttributeResourceValue(parser, ATTR_TITLE, 0); + final int iconId = getAttributeResourceValue(parser, ATTR_ICON, 0); + + if (titleResId == 0 || iconId == 0) { + if (LOGD) Log.d(TAG, "Ignoring shortcut"); + return -1; + } + + if (TextUtils.isEmpty(url) || !Patterns.WEB_URL.matcher(url).matches()) { + if (LOGD) Log.d(TAG, "Ignoring shortcut, invalid url: " + url); + return -1; + } + Drawable icon = res.getDrawable(iconId); + if (icon == null) { + if (LOGD) Log.d(TAG, "Ignoring shortcut, can't load icon"); + return -1; + } + + ItemInfo.writeBitmap(mValues, Utilities.createIconBitmap(icon, mContext)); + final Intent intent = new Intent(Intent.ACTION_VIEW, null) + .setData(Uri.parse(url)) + .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | + Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); + return addShortcut(res.getString(titleResId), intent, Favorites.ITEM_TYPE_SHORTCUT); + } + } + + private class AppWidgetParser implements TagParser { + + @Override + public long parseAndAdd(XmlResourceParser parser, Resources res) + throws XmlPullParserException, IOException { + final String packageName = getAttributeValue(parser, ATTR_PACKAGE_NAME); + final String className = getAttributeValue(parser, ATTR_CLASS_NAME); + if (TextUtils.isEmpty(packageName) || TextUtils.isEmpty(className)) { + if (LOGD) Log.d(TAG, "Skipping invalid <favorite> with no component"); + return -1; + } + + ComponentName cn = new ComponentName(packageName, className); + try { + mPackageManager.getReceiverInfo(cn, 0); + } catch (Exception e) { + String[] packages = mPackageManager.currentToCanonicalPackageNames( + new String[] { packageName }); + cn = new ComponentName(packages[0], className); + try { + mPackageManager.getReceiverInfo(cn, 0); + } catch (Exception e1) { + if (LOGD) Log.d(TAG, "Can't find widget provider: " + className); + return -1; + } + } + + mValues.put(Favorites.SPANX, getAttributeValue(parser, ATTR_SPAN_X)); + mValues.put(Favorites.SPANY, getAttributeValue(parser, ATTR_SPAN_Y)); + + // Read the extras + Bundle extras = new Bundle(); + int widgetDepth = parser.getDepth(); + int type; + while ((type = parser.next()) != XmlPullParser.END_TAG || + parser.getDepth() > widgetDepth) { + if (type != XmlPullParser.START_TAG) { + continue; + } + + if (TAG_EXTRA.equals(parser.getName())) { + String key = getAttributeValue(parser, ATTR_KEY); + String value = getAttributeValue(parser, ATTR_VALUE); + if (key != null && value != null) { + extras.putString(key, value); + } else { + throw new RuntimeException("Widget extras must have a key and value"); + } + } else { + throw new RuntimeException("Widgets can contain only extras"); + } + } + + final AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(mContext); + long insertedId = -1; + try { + int appWidgetId = mAppWidgetHost.allocateAppWidgetId(); + + if (!appWidgetManager.bindAppWidgetIdIfAllowed(appWidgetId, cn)) { + if (LOGD) Log.e(TAG, "Unable to bind app widget id " + cn); + return -1; + } + + mValues.put(Favorites.ITEM_TYPE, Favorites.ITEM_TYPE_APPWIDGET); + mValues.put(Favorites.APPWIDGET_ID, appWidgetId); + mValues.put(Favorites.APPWIDGET_PROVIDER, cn.flattenToString()); + mValues.put(Favorites._ID, mCallback.generateNewItemId()); + insertedId = mCallback.insertAndCheck(mDb, mValues); + if (insertedId < 0) { + mAppWidgetHost.deleteAppWidgetId(appWidgetId); + return insertedId; + } + + // Send a broadcast to configure the widget + if (!extras.isEmpty()) { + Intent intent = new Intent(ACTION_APPWIDGET_DEFAULT_WORKSPACE_CONFIGURE); + intent.setComponent(cn); + intent.putExtras(extras); + intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId); + mContext.sendBroadcast(intent); + } + } catch (RuntimeException ex) { + if (LOGD) Log.e(TAG, "Problem allocating appWidgetId", ex); + } + return insertedId; + } + } + + private class FolderParser implements TagParser { + private final HashMap<String, TagParser> mFolderElements = getFolderElementsMap(); + + @Override + public long parseAndAdd(XmlResourceParser parser, Resources res) + throws XmlPullParserException, IOException { + final String title; + final int titleResId = getAttributeResourceValue(parser, ATTR_TITLE, 0); + if (titleResId != 0) { + title = res.getString(titleResId); + } else { + title = mContext.getResources().getString(R.string.folder_name); + } + + mValues.put(Favorites.TITLE, title); + mValues.put(Favorites.ITEM_TYPE, Favorites.ITEM_TYPE_FOLDER); + mValues.put(Favorites.SPANX, 1); + mValues.put(Favorites.SPANY, 1); + mValues.put(Favorites._ID, mCallback.generateNewItemId()); + long folderId = mCallback.insertAndCheck(mDb, mValues); + if (folderId < 0) { + if (LOGD) Log.e(TAG, "Unable to add folder"); + return -1; + } + + final ContentValues myValues = new ContentValues(mValues); + ArrayList<Long> folderItems = new ArrayList<Long>(); + + int type; + int folderDepth = parser.getDepth(); + while ((type = parser.next()) != XmlPullParser.END_TAG || + parser.getDepth() > folderDepth) { + if (type != XmlPullParser.START_TAG) { + continue; + } + mValues.clear(); + mValues.put(Favorites.CONTAINER, folderId); + + TagParser tagParser = mFolderElements.get(parser.getName()); + if (tagParser != null) { + final long id = tagParser.parseAndAdd(parser, res); + if (id >= 0) { + folderItems.add(id); + } + } else { + throw new RuntimeException("Invalid folder item " + parser.getName()); + } + } + + long addedId = folderId; + + // We can only have folders with >= 2 items, so we need to remove the + // folder and clean up if less than 2 items were included, or some + // failed to add, and less than 2 were actually added + if (folderItems.size() < 2) { + // Delete the folder + Uri uri = Favorites.getContentUri(folderId, false); + SqlArguments args = new SqlArguments(uri, null, null); + mDb.delete(args.table, args.where, args.args); + addedId = -1; + + // If we have a single item, promote it to where the folder + // would have been. + if (folderItems.size() == 1) { + final ContentValues childValues = new ContentValues(); + copyInteger(myValues, childValues, Favorites.CONTAINER); + copyInteger(myValues, childValues, Favorites.SCREEN); + copyInteger(myValues, childValues, Favorites.CELLX); + copyInteger(myValues, childValues, Favorites.CELLY); + + addedId = folderItems.get(0); + mDb.update(LauncherProvider.TABLE_FAVORITES, childValues, + Favorites._ID + "=" + addedId, null); + } + } + return addedId; + } + } + + private static final void beginDocument(XmlPullParser parser, String firstElementName) + throws XmlPullParserException, IOException { + int type; + while ((type = parser.next()) != XmlPullParser.START_TAG + && type != XmlPullParser.END_DOCUMENT); + + if (type != XmlPullParser.START_TAG) { + throw new XmlPullParserException("No start tag found"); + } + + if (!parser.getName().equals(firstElementName)) { + throw new XmlPullParserException("Unexpected start tag: found " + parser.getName() + + ", expected " + firstElementName); + } + } + + /** + * Return attribute value, attempting launcher-specific namespace first + * before falling back to anonymous attribute. + */ + private static String getAttributeValue(XmlResourceParser parser, String attribute) { + String value = parser.getAttributeValue( + "http://schemas.android.com/apk/res-auto/com.android.launcher3", attribute); + if (value == null) { + value = parser.getAttributeValue(null, attribute); + } + return value; + } + + /** + * Return attribute resource value, attempting launcher-specific namespace + * first before falling back to anonymous attribute. + */ + private static int getAttributeResourceValue(XmlResourceParser parser, String attribute, + int defaultValue) { + int value = parser.getAttributeResourceValue( + "http://schemas.android.com/apk/res-auto/com.android.launcher3", attribute, + defaultValue); + if (value == defaultValue) { + value = parser.getAttributeResourceValue(null, attribute, defaultValue); + } + return value; + } + + public static interface LayoutParserCallback { + long generateNewItemId(); + + long insertAndCheck(SQLiteDatabase db, ContentValues values); + } + + private static void copyInteger(ContentValues from, ContentValues to, String key) { + to.put(key, from.getAsInteger(key)); + } +} diff --git a/src/com/android/launcher3/BorderCropDrawable.java b/src/com/android/launcher3/BorderCropDrawable.java new file mode 100644 index 000000000..caf497d9b --- /dev/null +++ b/src/com/android/launcher3/BorderCropDrawable.java @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2014 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.graphics.Canvas; +import android.graphics.ColorFilter; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; + +public class BorderCropDrawable extends Drawable { + + private final Drawable mChild; + private final Rect mBoundsShift; + private final Rect mPadding; + + BorderCropDrawable(Drawable child, boolean cropLeft, + boolean cropTop, boolean cropRight, boolean cropBottom) { + mChild = child; + + mBoundsShift = new Rect(); + mPadding = new Rect(); + mChild.getPadding(mPadding); + + if (cropLeft) { + mBoundsShift.left = -mPadding.left; + mPadding.left = 0; + } + if (cropTop) { + mBoundsShift.top = -mPadding.top; + mPadding.top = 0; + } + if (cropRight) { + mBoundsShift.right = mPadding.right; + mPadding.right = 0; + } + if (cropBottom) { + mBoundsShift.bottom = mPadding.bottom; + mPadding.bottom = 0; + } + } + + @Override + protected void onBoundsChange(Rect bounds) { + mChild.setBounds( + bounds.left + mBoundsShift.left, + bounds.top + mBoundsShift.top, + bounds.right + mBoundsShift.right, + bounds.bottom + mBoundsShift.bottom); + } + + @Override + public boolean getPadding(Rect padding) { + padding.set(mPadding); + return (padding.left | padding.top | padding.right | padding.bottom) != 0; + } + + @Override + public void draw(Canvas canvas) { + mChild.draw(canvas); + } + + @Override + public int getOpacity() { + return mChild.getOpacity(); + } + + @Override + public void setAlpha(int alpha) { + mChild.setAlpha(alpha); + } + + @Override + public void setColorFilter(ColorFilter cf) { + mChild.setColorFilter(cf); + } +} diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java index ee42904dd..a368796bd 100644 --- a/src/com/android/launcher3/BubbleTextView.java +++ b/src/com/android/launcher3/BubbleTextView.java @@ -17,16 +17,20 @@ package com.android.launcher3; import android.content.Context; +import android.content.res.ColorStateList; import android.content.res.Resources; +import android.content.res.Resources.Theme; +import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.Canvas; -import android.graphics.Rect; import android.graphics.Region; -import android.graphics.Region.Op; import android.graphics.drawable.Drawable; import android.util.AttributeSet; +import android.util.SparseArray; import android.util.TypedValue; +import android.view.KeyEvent; import android.view.MotionEvent; +import android.view.ViewConfiguration; import android.widget.TextView; /** @@ -35,48 +39,57 @@ import android.widget.TextView; * too aggressive. */ public class BubbleTextView extends TextView { - static final float SHADOW_LARGE_RADIUS = 4.0f; - static final float SHADOW_SMALL_RADIUS = 1.75f; - static final float SHADOW_Y_OFFSET = 2.0f; - static final int SHADOW_LARGE_COLOUR = 0xDD000000; - static final int SHADOW_SMALL_COLOUR = 0xCC000000; - static final float PADDING_H = 8.0f; - static final float PADDING_V = 3.0f; - private int mPrevAlpha = -1; + private static SparseArray<Theme> sPreloaderThemes = new SparseArray<>(2); + + private static final float SHADOW_LARGE_RADIUS = 4.0f; + private static final float SHADOW_SMALL_RADIUS = 1.75f; + private static final float SHADOW_Y_OFFSET = 2.0f; + private static final int SHADOW_LARGE_COLOUR = 0xDD000000; + private static final int SHADOW_SMALL_COLOUR = 0xCC000000; + static final float PADDING_V = 3.0f; private HolographicOutlineHelper mOutlineHelper; - private final Canvas mTempCanvas = new Canvas(); - private final Rect mTempRect = new Rect(); - private boolean mDidInvalidateForPressedState; - private Bitmap mPressedOrFocusedBackground; - private int mFocusedOutlineColor; - private int mFocusedGlowColor; - private int mPressedOutlineColor; - private int mPressedGlowColor; + private Bitmap mPressedBackground; + + private float mSlop; private int mTextColor; - private boolean mShadowsEnabled = true; + private final boolean mCustomShadowsEnabled; private boolean mIsTextVisible; + // TODO: Remove custom background handling code, as no instance of BubbleTextView use any + // background. private boolean mBackgroundSizeChanged; - private Drawable mBackground; + private final Drawable mBackground; private boolean mStayPressed; + private boolean mIgnorePressedStateChange; private CheckLongPressHelper mLongPressHelper; public BubbleTextView(Context context) { - super(context); - init(); + this(context, null, 0); } public BubbleTextView(Context context, AttributeSet attrs) { - super(context, attrs); - init(); + this(context, attrs, 0); } public BubbleTextView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); + + TypedArray a = context.obtainStyledAttributes(attrs, + R.styleable.BubbleTextView, defStyle, 0); + mCustomShadowsEnabled = a.getBoolean(R.styleable.BubbleTextView_customShadows, true); + a.recycle(); + + if (mCustomShadowsEnabled) { + // Draw the background itself as the parent is drawn twice. + mBackground = getBackground(); + setBackground(null); + } else { + mBackground = null; + } init(); } @@ -87,34 +100,62 @@ public class BubbleTextView extends TextView { LauncherAppState app = LauncherAppState.getInstance(); DeviceProfile grid = app.getDynamicGrid().getDeviceProfile(); setTextSize(TypedValue.COMPLEX_UNIT_PX, grid.iconTextSizePx); - setTextColor(getResources().getColor(R.color.workspace_icon_text_color)); } private void init() { mLongPressHelper = new CheckLongPressHelper(this); - mBackground = getBackground(); mOutlineHelper = HolographicOutlineHelper.obtain(getContext()); + if (mCustomShadowsEnabled) { + setShadowLayer(SHADOW_LARGE_RADIUS, 0.0f, SHADOW_Y_OFFSET, SHADOW_LARGE_COLOUR); + } + } - final Resources res = getContext().getResources(); - mFocusedOutlineColor = mFocusedGlowColor = mPressedOutlineColor = mPressedGlowColor = - res.getColor(R.color.outline_color); - - setShadowLayer(SHADOW_LARGE_RADIUS, 0.0f, SHADOW_Y_OFFSET, SHADOW_LARGE_COLOUR); + public void applyFromShortcutInfo(ShortcutInfo info, IconCache iconCache, + boolean setDefaultPadding) { + applyFromShortcutInfo(info, iconCache, setDefaultPadding, false); } - public void applyFromShortcutInfo(ShortcutInfo info, IconCache iconCache) { + public void applyFromShortcutInfo(ShortcutInfo info, IconCache iconCache, + boolean setDefaultPadding, boolean promiseStateChanged) { Bitmap b = info.getIcon(iconCache); LauncherAppState app = LauncherAppState.getInstance(); + + FastBitmapDrawable iconDrawable = Utilities.createIconDrawable(b); + iconDrawable.setGhostModeEnabled(info.isDisabled); + + setCompoundDrawables(null, iconDrawable, null, null); + if (setDefaultPadding) { + DeviceProfile grid = app.getDynamicGrid().getDeviceProfile(); + setCompoundDrawablePadding(grid.iconDrawablePaddingPx); + } + if (info.contentDescription != null) { + setContentDescription(info.contentDescription); + } + setText(info.title); + setTag(info); + + if (promiseStateChanged || info.isPromise()) { + applyState(promiseStateChanged); + } + } + + public void applyFromApplicationInfo(AppInfo info) { + LauncherAppState app = LauncherAppState.getInstance(); DeviceProfile grid = app.getDynamicGrid().getDeviceProfile(); - setCompoundDrawables(null, - Utilities.createIconDrawable(b), null, null); + Drawable topDrawable = Utilities.createIconDrawable(info.iconBitmap); + topDrawable.setBounds(0, 0, grid.allAppsIconSizePx, grid.allAppsIconSizePx); + setCompoundDrawables(null, topDrawable, null, null); setCompoundDrawablePadding(grid.iconDrawablePaddingPx); setText(info.title); + if (info.contentDescription != null) { + setContentDescription(info.contentDescription); + } setTag(info); } + @Override protected boolean setFrame(int left, int top, int right, int bottom) { if (getLeft() != left || getRight() != right || getTop() != top || getBottom() != bottom) { @@ -137,90 +178,19 @@ public class BubbleTextView extends TextView { } @Override - protected void drawableStateChanged() { - if (isPressed()) { - // In this case, we have already created the pressed outline on ACTION_DOWN, - // so we just need to do an invalidate to trigger draw - if (!mDidInvalidateForPressedState) { - setCellLayoutPressedOrFocusedIcon(); - } - } else { - // Otherwise, either clear the pressed/focused background, or create a background - // for the focused state - final boolean backgroundEmptyBefore = mPressedOrFocusedBackground == null; - if (!mStayPressed) { - mPressedOrFocusedBackground = null; - } - if (isFocused()) { - if (getLayout() == null) { - // In some cases, we get focus before we have been layed out. Set the - // background to null so that it will get created when the view is drawn. - mPressedOrFocusedBackground = null; - } else { - mPressedOrFocusedBackground = createGlowingOutline( - mTempCanvas, mFocusedGlowColor, mFocusedOutlineColor); - } - mStayPressed = false; - setCellLayoutPressedOrFocusedIcon(); - } - final boolean backgroundEmptyNow = mPressedOrFocusedBackground == null; - if (!backgroundEmptyBefore && backgroundEmptyNow) { - setCellLayoutPressedOrFocusedIcon(); - } - } + public void setPressed(boolean pressed) { + super.setPressed(pressed); - Drawable d = mBackground; - if (d != null && d.isStateful()) { - d.setState(getDrawableState()); + if (!mIgnorePressedStateChange) { + updateIconState(); } - super.drawableStateChanged(); } - /** - * Draw this BubbleTextView into the given Canvas. - * - * @param destCanvas the canvas to draw on - * @param padding the horizontal and vertical padding to use when drawing - */ - private void drawWithPadding(Canvas destCanvas, int padding) { - final Rect clipRect = mTempRect; - getDrawingRect(clipRect); - - // adjust the clip rect so that we don't include the text label - clipRect.bottom = - getExtendedPaddingTop() - (int) BubbleTextView.PADDING_V + getLayout().getLineTop(0); - - // Draw the View into the bitmap. - // The translate of scrollX and scrollY is necessary when drawing TextViews, because - // they set scrollX and scrollY to large values to achieve centered text - destCanvas.save(); - destCanvas.scale(getScaleX(), getScaleY(), - (getWidth() + padding) / 2, (getHeight() + padding) / 2); - destCanvas.translate(-getScrollX() + padding / 2, -getScrollY() + padding / 2); - destCanvas.clipRect(clipRect, Op.REPLACE); - draw(destCanvas); - destCanvas.restore(); - } - - public void setGlowColor(int color) { - mFocusedOutlineColor = mFocusedGlowColor = mPressedOutlineColor = mPressedGlowColor = color; - } - - /** - * Returns a new bitmap to be used as the object outline, e.g. to visualize the drop location. - * Responsibility for the bitmap is transferred to the caller. - */ - private Bitmap createGlowingOutline(Canvas canvas, int outlineColor, int glowColor) { - final int padding = mOutlineHelper.mMaxOuterBlurRadius; - final Bitmap b = Bitmap.createBitmap( - getWidth() + padding, getHeight() + padding, Bitmap.Config.ARGB_8888); - - canvas.setBitmap(b); - drawWithPadding(canvas, padding); - mOutlineHelper.applyExtraThickExpensiveOutlineWithBlur(b, canvas, glowColor, outlineColor); - canvas.setBitmap(null); - - return b; + private void updateIconState() { + Drawable top = getCompoundDrawables()[1]; + if (top instanceof FastBitmapDrawable) { + ((FastBitmapDrawable) top).setPressed(isPressed() || mStayPressed); + } } @Override @@ -231,20 +201,11 @@ public class BubbleTextView extends TextView { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: - // So that the pressed outline is visible immediately when isPressed() is true, + // So that the pressed outline is visible immediately on setStayPressed(), // we pre-create it on ACTION_DOWN (it takes a small but perceptible amount of time // to create it) - if (mPressedOrFocusedBackground == null) { - mPressedOrFocusedBackground = createGlowingOutline( - mTempCanvas, mPressedGlowColor, mPressedOutlineColor); - } - // Invalidate so the pressed state is visible, or set a flag so we know that we - // have to call invalidate as soon as the state is "pressed" - if (isPressed()) { - mDidInvalidateForPressedState = true; - setCellLayoutPressedOrFocusedIcon(); - } else { - mDidInvalidateForPressedState = false; + if (mPressedBackground == null) { + mPressedBackground = mOutlineHelper.createMediumDropShadow(this); } mLongPressHelper.postCheckForLongPress(); @@ -254,11 +215,16 @@ public class BubbleTextView extends TextView { // If we've touched down and up on an item, and it's still not "pressed", then // destroy the pressed outline if (!isPressed()) { - mPressedOrFocusedBackground = null; + mPressedBackground = null; } mLongPressHelper.cancelLongPress(); break; + case MotionEvent.ACTION_MOVE: + if (!Utilities.pointInView(this, event.getX(), event.getY(), mSlop)) { + mLongPressHelper.cancelLongPress(); + } + break; } return result; } @@ -266,37 +232,52 @@ public class BubbleTextView extends TextView { void setStayPressed(boolean stayPressed) { mStayPressed = stayPressed; if (!stayPressed) { - mPressedOrFocusedBackground = null; + mPressedBackground = null; } - setCellLayoutPressedOrFocusedIcon(); - } - void setCellLayoutPressedOrFocusedIcon() { + // Only show the shadow effect when persistent pressed state is set. if (getParent() instanceof ShortcutAndWidgetContainer) { - ShortcutAndWidgetContainer parent = (ShortcutAndWidgetContainer) getParent(); - if (parent != null) { - CellLayout layout = (CellLayout) parent.getParent(); - layout.setPressedOrFocusedIcon((mPressedOrFocusedBackground != null) ? this : null); - } + CellLayout layout = (CellLayout) getParent().getParent(); + layout.setPressedIcon(this, mPressedBackground, mOutlineHelper.shadowBitmapPadding); } + + updateIconState(); } - void clearPressedOrFocusedBackground() { - mPressedOrFocusedBackground = null; - setCellLayoutPressedOrFocusedIcon(); + void clearPressedBackground() { + setPressed(false); + setStayPressed(false); } - Bitmap getPressedOrFocusedBackground() { - return mPressedOrFocusedBackground; + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + if (super.onKeyDown(keyCode, event)) { + // Pre-create shadow so show immediately on click. + if (mPressedBackground == null) { + mPressedBackground = mOutlineHelper.createMediumDropShadow(this); + } + return true; + } + return false; } - int getPressedOrFocusedBackgroundPadding() { - return mOutlineHelper.mMaxOuterBlurRadius / 2; + @Override + public boolean onKeyUp(int keyCode, KeyEvent event) { + // Unlike touch events, keypress event propagate pressed state change immediately, + // without waiting for onClickHandler to execute. Disable pressed state changes here + // to avoid flickering. + mIgnorePressedStateChange = true; + boolean result = super.onKeyUp(keyCode, event); + + mPressedBackground = null; + mIgnorePressedStateChange = false; + updateIconState(); + return result; } @Override public void draw(Canvas canvas) { - if (!mShadowsEnabled) { + if (!mCustomShadowsEnabled) { super.draw(canvas); return; } @@ -342,7 +323,14 @@ public class BubbleTextView extends TextView { @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); + if (mBackground != null) mBackground.setCallback(this); + Drawable top = getCompoundDrawables()[1]; + + if (top instanceof PreloadIconDrawable) { + ((PreloadIconDrawable) top).applyTheme(getPreloaderTheme()); + } + mSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop(); } @Override @@ -357,10 +345,10 @@ public class BubbleTextView extends TextView { super.setTextColor(color); } - public void setShadowsEnabled(boolean enabled) { - mShadowsEnabled = enabled; - getPaint().clearShadowLayer(); - invalidate(); + @Override + public void setTextColor(ColorStateList colors) { + mTextColor = colors.getDefaultColor(); + super.setTextColor(colors); } public void setTextVisibility(boolean visible) { @@ -379,10 +367,6 @@ public class BubbleTextView extends TextView { @Override protected boolean onSetAlpha(int alpha) { - if (mPrevAlpha != alpha) { - mPrevAlpha = alpha; - super.onSetAlpha(alpha); - } return true; } @@ -392,4 +376,45 @@ public class BubbleTextView extends TextView { mLongPressHelper.cancelLongPress(); } + + public void applyState(boolean promiseStateChanged) { + if (getTag() instanceof ShortcutInfo) { + ShortcutInfo info = (ShortcutInfo) getTag(); + final boolean isPromise = info.isPromise(); + final int progressLevel = isPromise ? + ((info.hasStatusFlag(ShortcutInfo.FLAG_INSTALL_SESSION_ACTIVE) ? + info.getInstallProgress() : 0)) : 100; + + Drawable[] drawables = getCompoundDrawables(); + Drawable top = drawables[1]; + if (top != null) { + final PreloadIconDrawable preloadDrawable; + if (top instanceof PreloadIconDrawable) { + preloadDrawable = (PreloadIconDrawable) top; + } else { + preloadDrawable = new PreloadIconDrawable(top, getPreloaderTheme()); + setCompoundDrawables(drawables[0], preloadDrawable, drawables[2], drawables[3]); + } + + preloadDrawable.setLevel(progressLevel); + if (promiseStateChanged) { + preloadDrawable.maybePerformFinishedAnimation(); + } + } + } + } + + private Theme getPreloaderTheme() { + Object tag = getTag(); + int style = ((tag != null) && (tag instanceof ShortcutInfo) && + (((ShortcutInfo) tag).container >= 0)) ? R.style.PreloadIcon_Folder + : R.style.PreloadIcon; + Theme theme = sPreloaderThemes.get(style); + if (theme == null) { + theme = getResources().newTheme(); + theme.applyStyle(style, true); + sPreloaderThemes.put(style, theme); + } + return theme; + } } diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java index 2436a51a3..0ff1ef4ad 100644 --- a/src/com/android/launcher3/CellLayout.java +++ b/src/com/android/launcher3/CellLayout.java @@ -30,8 +30,6 @@ import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Point; -import android.graphics.PorterDuff; -import android.graphics.PorterDuffXfermode; import android.graphics.Rect; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; @@ -73,11 +71,8 @@ public class CellLayout extends ViewGroup { private int mWidthGap; private int mHeightGap; private int mMaxGap; - private boolean mScrollingTransformsDirty = false; private boolean mDropPending = false; - - private final Rect mRect = new Rect(); - private final CellInfo mCellInfo = new CellInfo(); + private boolean mIsDragTarget = true; // These are temporary variables to prevent having to allocate a new object just to // return an (x, y) value from helper functions. Do NOT use them to maintain other state. @@ -128,7 +123,7 @@ public class CellLayout extends ViewGroup { private int mDragOutlineCurrent = 0; private final Paint mDragOutlinePaint = new Paint(); - private BubbleTextView mPressedOrFocusedIcon; + private final FastBitmapView mTouchFeedbackView; private HashMap<CellLayout.LayoutParams, Animator> mReorderAnimators = new HashMap<CellLayout.LayoutParams, Animator>(); @@ -172,8 +167,6 @@ public class CellLayout extends ViewGroup { private Rect mTempRect = new Rect(); - private final static PorterDuffXfermode sAddBlendMode = - new PorterDuffXfermode(PorterDuff.Mode.ADD); private final static Paint sPaint = new Paint(); public CellLayout(Context context) { @@ -295,6 +288,9 @@ public class CellLayout extends ViewGroup { mShortcutsAndWidgets.setCellDimensions(mCellWidth, mCellHeight, mWidthGap, mHeightGap, mCountX, mCountY); + mTouchFeedbackView = new FastBitmapView(context); + // Make the feedback view large enough to hold the blur bitmap. + addView(mTouchFeedbackView, (int) (grid.cellWidthPx * 1.5), (int) (grid.cellHeightPx * 1.5)); addView(mShortcutsAndWidgets); } @@ -341,14 +337,6 @@ public class CellLayout extends ViewGroup { return mDropPending; } - private void invalidateBubbleTextView(BubbleTextView icon) { - final int padding = icon.getPressedOrFocusedBackgroundPadding(); - invalidate(icon.getLeft() + getPaddingLeft() - padding, - icon.getTop() + getPaddingTop() - padding, - icon.getRight() + getPaddingLeft() + padding, - icon.getBottom() + getPaddingTop() + padding); - } - void setOverScrollAmount(float r, boolean left) { if (left && mOverScrollForegroundDrawable != mOverScrollLeft) { mOverScrollForegroundDrawable = mOverScrollLeft; @@ -362,24 +350,23 @@ public class CellLayout extends ViewGroup { invalidate(); } - void setPressedOrFocusedIcon(BubbleTextView icon) { - // We draw the pressed or focused BubbleTextView's background in CellLayout because it - // requires an expanded clip rect (due to the glow's blur radius) - BubbleTextView oldIcon = mPressedOrFocusedIcon; - mPressedOrFocusedIcon = icon; - if (oldIcon != null) { - invalidateBubbleTextView(oldIcon); - } - if (mPressedOrFocusedIcon != null) { - invalidateBubbleTextView(mPressedOrFocusedIcon); - } - } - - void setIsDragOverlapping(boolean isDragOverlapping) { - if (mIsDragOverlapping != isDragOverlapping) { - mIsDragOverlapping = isDragOverlapping; - setUseActiveGlowBackground(mIsDragOverlapping); - invalidate(); + void setPressedIcon(BubbleTextView icon, Bitmap background, int padding) { + if (icon == null || background == null) { + mTouchFeedbackView.setBitmap(null); + mTouchFeedbackView.animate().cancel(); + } else { + int offset = getMeasuredWidth() - getPaddingLeft() - getPaddingRight() + - (mCountX * mCellWidth); + mTouchFeedbackView.setTranslationX(icon.getLeft() + (int) Math.ceil(offset / 2f) + - padding); + mTouchFeedbackView.setTranslationY(icon.getTop() - padding); + if (mTouchFeedbackView.setBitmap(background)) { + mTouchFeedbackView.setAlpha(0); + mTouchFeedbackView.animate().alpha(1) + .setDuration(FastBitmapDrawable.CLICK_FEEDBACK_DURATION) + .setInterpolator(FastBitmapDrawable.CLICK_FEEDBACK_INTERPOLATOR) + .start(); + } } } @@ -391,27 +378,26 @@ public class CellLayout extends ViewGroup { mDrawBackground = false; } - boolean getIsDragOverlapping() { - return mIsDragOverlapping; + void disableDragTarget() { + mIsDragTarget = false; } - protected void setOverscrollTransformsDirty(boolean dirty) { - mScrollingTransformsDirty = dirty; + boolean isDragTarget() { + return mIsDragTarget; } - protected void resetOverscrollTransforms() { - if (mScrollingTransformsDirty) { - setOverscrollTransformsDirty(false); - setTranslationX(0); - setRotationY(0); - // It doesn't matter if we pass true or false here, the important thing is that we - // pass 0, which results in the overscroll drawable not being drawn any more. - setOverScrollAmount(0, false); - setPivotX(getMeasuredWidth() / 2); - setPivotY(getMeasuredHeight() / 2); + void setIsDragOverlapping(boolean isDragOverlapping) { + if (mIsDragOverlapping != isDragOverlapping) { + mIsDragOverlapping = isDragOverlapping; + setUseActiveGlowBackground(mIsDragOverlapping); + invalidate(); } } + boolean getIsDragOverlapping() { + return mIsDragOverlapping; + } + @Override protected void onDraw(Canvas canvas) { // When we're large, we are either drawn in a "hover" state (ie when dragging an item to @@ -447,23 +433,6 @@ public class CellLayout extends ViewGroup { } } - // We draw the pressed or focused BubbleTextView's background in CellLayout because it - // requires an expanded clip rect (due to the glow's blur radius) - if (mPressedOrFocusedIcon != null) { - final int padding = mPressedOrFocusedIcon.getPressedOrFocusedBackgroundPadding(); - final Bitmap b = mPressedOrFocusedIcon.getPressedOrFocusedBackground(); - if (b != null) { - int offset = getMeasuredWidth() - getPaddingLeft() - getPaddingRight() - - (mCountX * mCellWidth); - int left = getPaddingLeft() + (int) Math.ceil(offset / 2f); - int top = getPaddingTop(); - canvas.drawBitmap(b, - mPressedOrFocusedIcon.getLeft() + left - padding, - mPressedOrFocusedIcon.getTop() + top - padding, - null); - } - } - if (DEBUG_VISUALIZE_OCCUPIED) { int[] pt = new int[2]; ColorDrawable cd = new ColorDrawable(Color.RED); @@ -582,7 +551,15 @@ public class CellLayout extends ViewGroup { } public void restoreInstanceState(SparseArray<Parcelable> states) { - dispatchRestoreInstanceState(states); + try { + dispatchRestoreInstanceState(states); + } catch (IllegalArgumentException ex) { + if (LauncherAppState.isDogfoodBuild()) { + throw ex; + } + // Mismatched viewId / viewType preventing restore. Skip restore on production builds. + Log.e(TAG, "Ignoring an error while restoring a view instance state", ex); + } } @Override @@ -699,103 +676,17 @@ public class CellLayout extends ViewGroup { } @Override - protected void onAttachedToWindow() { - super.onAttachedToWindow(); - if (getParent() instanceof Workspace) { - Workspace workspace = (Workspace) getParent(); - mCellInfo.screenId = workspace.getIdForScreen(this); - } - } - - public void setTagToCellInfoForPoint(int touchX, int touchY) { - final CellInfo cellInfo = mCellInfo; - Rect frame = mRect; - final int x = touchX + getScrollX(); - final int y = touchY + getScrollY(); - final int count = mShortcutsAndWidgets.getChildCount(); - - boolean found = false; - for (int i = count - 1; i >= 0; i--) { - final View child = mShortcutsAndWidgets.getChildAt(i); - final LayoutParams lp = (LayoutParams) child.getLayoutParams(); - - if ((child.getVisibility() == VISIBLE || child.getAnimation() != null) && - lp.isLockedToGrid) { - child.getHitRect(frame); - - float scale = child.getScaleX(); - frame = new Rect(child.getLeft(), child.getTop(), child.getRight(), - child.getBottom()); - // The child hit rect is relative to the CellLayoutChildren parent, so we need to - // offset that by this CellLayout's padding to test an (x,y) point that is relative - // to this view. - frame.offset(getPaddingLeft(), getPaddingTop()); - frame.inset((int) (frame.width() * (1f - scale) / 2), - (int) (frame.height() * (1f - scale) / 2)); - - if (frame.contains(x, y)) { - cellInfo.cell = child; - cellInfo.cellX = lp.cellX; - cellInfo.cellY = lp.cellY; - cellInfo.spanX = lp.cellHSpan; - cellInfo.spanY = lp.cellVSpan; - found = true; - break; - } - } - } - - mLastDownOnOccupiedCell = found; - - if (!found) { - final int cellXY[] = mTmpXY; - pointToCellExact(x, y, cellXY); - - cellInfo.cell = null; - cellInfo.cellX = cellXY[0]; - cellInfo.cellY = cellXY[1]; - cellInfo.spanX = 1; - cellInfo.spanY = 1; - } - setTag(cellInfo); - } - - @Override public boolean onInterceptTouchEvent(MotionEvent ev) { // First we clear the tag to ensure that on every touch down we start with a fresh slate, // even in the case where we return early. Not clearing here was causing bugs whereby on // long-press we'd end up picking up an item from a previous drag operation. - final int action = ev.getAction(); - - if (action == MotionEvent.ACTION_DOWN) { - clearTagCellInfo(); - } - if (mInterceptTouchListener != null && mInterceptTouchListener.onTouch(this, ev)) { return true; } - if (action == MotionEvent.ACTION_DOWN) { - setTagToCellInfoForPoint((int) ev.getX(), (int) ev.getY()); - } - return false; } - private void clearTagCellInfo() { - final CellInfo cellInfo = mCellInfo; - cellInfo.cell = null; - cellInfo.cellX = -1; - cellInfo.cellY = -1; - cellInfo.spanX = 0; - cellInfo.spanY = 0; - setTag(cellInfo); - } - - public CellInfo getTag() { - return (CellInfo) super.getTag(); - } - /** * Given a point, return the cell that strictly encloses that point * @param x X coordinate of the point @@ -1049,6 +940,7 @@ public class CellLayout extends ViewGroup { } public void setBackgroundAlphaMultiplier(float multiplier) { + if (mBackgroundAlphaMultiplier != multiplier) { mBackgroundAlphaMultiplier = multiplier; invalidate(); @@ -1067,17 +959,11 @@ public class CellLayout extends ViewGroup { } public void setShortcutAndWidgetAlpha(float alpha) { - final int childCount = getChildCount(); - for (int i = 0; i < childCount; i++) { - getChildAt(i).setAlpha(alpha); - } + mShortcutsAndWidgets.setAlpha(alpha); } public ShortcutAndWidgetContainer getShortcutsAndWidgets() { - if (getChildCount() > 0) { - return (ShortcutAndWidgetContainer) getChildAt(0); - } - return null; + return mShortcutsAndWidgets; } public View getChildAt(int x, int y) { @@ -3360,6 +3246,16 @@ out: for (int i = x; i < x + spanX - 1 && x < xCount; i++) { long screenId; long container; + CellInfo(View v, ItemInfo info) { + cell = v; + cellX = info.cellX; + cellY = info.cellY; + spanX = info.spanX; + spanY = info.spanY; + screenId = info.screenId; + container = info.container; + } + @Override public String toString() { return "Cell[view=" + (cell == null ? "null" : cell.getClass()) diff --git a/src/com/android/launcher3/Cling.java b/src/com/android/launcher3/Cling.java deleted file mode 100644 index a6139ccbc..000000000 --- a/src/com/android/launcher3/Cling.java +++ /dev/null @@ -1,571 +0,0 @@ -/* - * Copyright (C) 2011 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.animation.Animator; -import android.animation.AnimatorListenerAdapter; -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.content.res.Resources; -import android.content.res.TypedArray; -import android.graphics.*; -import android.graphics.drawable.Drawable; -import android.util.AttributeSet; -import android.util.DisplayMetrics; -import android.view.FocusFinder; -import android.view.MotionEvent; -import android.view.View; -import android.view.ViewGroup; -import android.view.animation.AccelerateInterpolator; -import android.widget.FrameLayout; -import android.widget.TextView; - -public class Cling extends FrameLayout implements Insettable, View.OnClickListener, - View.OnLongClickListener, View.OnTouchListener { - - private static String FIRST_RUN_PORTRAIT = "first_run_portrait"; - private static String FIRST_RUN_LANDSCAPE = "first_run_landscape"; - - private static String WORKSPACE_PORTRAIT = "workspace_portrait"; - private static String WORKSPACE_LANDSCAPE = "workspace_landscape"; - private static String WORKSPACE_LARGE = "workspace_large"; - private static String WORKSPACE_CUSTOM = "workspace_custom"; - - private static String MIGRATION_PORTRAIT = "migration_portrait"; - private static String MIGRATION_LANDSCAPE = "migration_landscape"; - - private static String MIGRATION_WORKSPACE_PORTRAIT = "migration_workspace_portrait"; - private static String MIGRATION_WORKSPACE_LARGE_PORTRAIT = "migration_workspace_large_portrait"; - private static String MIGRATION_WORKSPACE_LANDSCAPE = "migration_workspace_landscape"; - - private static String FOLDER_PORTRAIT = "folder_portrait"; - private static String FOLDER_LANDSCAPE = "folder_landscape"; - private static String FOLDER_LARGE = "folder_large"; - - private static float FIRST_RUN_CIRCLE_BUFFER_DPS = 60; - private static float FIRST_RUN_MAX_CIRCLE_RADIUS_DPS = 180; - private static float WORKSPACE_INNER_CIRCLE_RADIUS_DPS = 50; - private static float WORKSPACE_OUTER_CIRCLE_RADIUS_DPS = 60; - private static float WORKSPACE_CIRCLE_Y_OFFSET_DPS = 30; - private static float MIGRATION_WORKSPACE_INNER_CIRCLE_RADIUS_DPS = 42; - private static float MIGRATION_WORKSPACE_OUTER_CIRCLE_RADIUS_DPS = 46; - - private Launcher mLauncher; - private boolean mIsInitialized; - private String mDrawIdentifier; - private Drawable mBackground; - - private int[] mTouchDownPt = new int[2]; - - private Drawable mFocusedHotseatApp; - private ComponentName mFocusedHotseatAppComponent; - private Rect mFocusedHotseatAppBounds; - - private Paint mErasePaint; - private Paint mBorderPaint; - private Paint mBubblePaint; - private Paint mDotPaint; - - private View mScrimView; - private int mBackgroundColor; - - private final Rect mInsets = new Rect(); - - public Cling(Context context) { - this(context, null, 0); - } - - public Cling(Context context, AttributeSet attrs) { - this(context, attrs, 0); - } - - public Cling(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - - TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.Cling, defStyle, 0); - mDrawIdentifier = a.getString(R.styleable.Cling_drawIdentifier); - a.recycle(); - - setClickable(true); - - } - - void init(Launcher l, View scrim) { - if (!mIsInitialized) { - mLauncher = l; - mScrimView = scrim; - mBackgroundColor = 0xcc000000; - setOnLongClickListener(this); - setOnClickListener(this); - setOnTouchListener(this); - - mErasePaint = new Paint(); - mErasePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY)); - mErasePaint.setColor(0xFFFFFF); - mErasePaint.setAlpha(0); - mErasePaint.setAntiAlias(true); - - mBorderPaint = new Paint(); - mBorderPaint.setColor(0xFFFFFFFF); - mBorderPaint.setAntiAlias(true); - - int circleColor = getResources().getColor( - R.color.first_run_cling_circle_background_color); - mBubblePaint = new Paint(); - mBubblePaint.setColor(circleColor); - mBubblePaint.setAntiAlias(true); - - mDotPaint = new Paint(); - mDotPaint.setColor(0x72BBED); - mDotPaint.setAntiAlias(true); - - mIsInitialized = true; - } - } - - void setFocusedHotseatApp(int drawableId, int appRank, ComponentName cn, String title, - String description) { - // Get the app to draw - Resources r = getResources(); - int appIconId = drawableId; - Hotseat hotseat = mLauncher.getHotseat(); - // Skip the focused app in the large layouts - if (!mDrawIdentifier.equals(WORKSPACE_LARGE) && - hotseat != null && appIconId > -1 && appRank > -1 && !title.isEmpty() && - !description.isEmpty()) { - // Set the app bounds - int x = hotseat.getCellXFromOrder(appRank); - int y = hotseat.getCellYFromOrder(appRank); - Rect pos = hotseat.getCellCoordinates(x, y); - LauncherAppState app = LauncherAppState.getInstance(); - DeviceProfile grid = app.getDynamicGrid().getDeviceProfile(); - mFocusedHotseatApp = getResources().getDrawable(appIconId); - mFocusedHotseatAppComponent = cn; - mFocusedHotseatAppBounds = new Rect(pos.left, pos.top, - pos.left + Utilities.sIconTextureWidth, - pos.top + Utilities.sIconTextureHeight); - Utilities.scaleRectAboutCenter(mFocusedHotseatAppBounds, - ((float) grid.hotseatIconSizePx / grid.iconSizePx)); - - // Set the title - TextView v = (TextView) findViewById(R.id.focused_hotseat_app_title); - if (v != null) { - v.setText(title); - } - - // Set the description - v = (TextView) findViewById(R.id.focused_hotseat_app_description); - if (v != null) { - v.setText(description); - } - - // Show the bubble - View bubble = findViewById(R.id.focused_hotseat_app_bubble); - bubble.setVisibility(View.VISIBLE); - } - } - - void setOpenFolderRect(Rect r) { - if (mDrawIdentifier.equals(FOLDER_LANDSCAPE) || - mDrawIdentifier.equals(FOLDER_LARGE)) { - ViewGroup vg = (ViewGroup) findViewById(R.id.folder_bubble); - ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams) vg.getLayoutParams(); - lp.topMargin = r.top - mInsets.bottom; - lp.leftMargin = r.right; - vg.setLayoutDirection(View.LAYOUT_DIRECTION_LTR); - vg.requestLayout(); - } - } - - void updateMigrationWorkspaceBubblePosition() { - DisplayMetrics metrics = new DisplayMetrics(); - mLauncher.getWindowManager().getDefaultDisplay().getMetrics(metrics); - - // Get the page indicator bounds - LauncherAppState app = LauncherAppState.getInstance(); - DeviceProfile grid = app.getDynamicGrid().getDeviceProfile(); - Rect pageIndicatorBounds = grid.getWorkspacePageIndicatorBounds(mInsets); - - if (mDrawIdentifier.equals(MIGRATION_WORKSPACE_PORTRAIT)) { - View bubble = findViewById(R.id.migration_workspace_cling_bubble); - ViewGroup.MarginLayoutParams lp = - (ViewGroup.MarginLayoutParams) bubble.getLayoutParams(); - lp.bottomMargin = grid.heightPx - pageIndicatorBounds.top; - bubble.requestLayout(); - } else if (mDrawIdentifier.equals(MIGRATION_WORKSPACE_LARGE_PORTRAIT)) { - View bubble = findViewById(R.id.content); - ViewGroup.MarginLayoutParams lp = - (ViewGroup.MarginLayoutParams) bubble.getLayoutParams(); - lp.bottomMargin = grid.heightPx - pageIndicatorBounds.top; - bubble.requestLayout(); - } else if (mDrawIdentifier.equals(MIGRATION_WORKSPACE_LANDSCAPE)) { - View bubble = findViewById(R.id.content); - ViewGroup.MarginLayoutParams lp = - (ViewGroup.MarginLayoutParams) bubble.getLayoutParams(); - if (grid.isLayoutRtl) { - lp.leftMargin = pageIndicatorBounds.right; - } else { - lp.rightMargin = (grid.widthPx - pageIndicatorBounds.left); - } - bubble.requestLayout(); - } - } - - void updateWorkspaceBubblePosition() { - DisplayMetrics metrics = new DisplayMetrics(); - mLauncher.getWindowManager().getDefaultDisplay().getMetrics(metrics); - - // Get the cut-out bounds - LauncherAppState app = LauncherAppState.getInstance(); - DeviceProfile grid = app.getDynamicGrid().getDeviceProfile(); - Rect cutOutBounds = getWorkspaceCutOutBounds(metrics); - - if (mDrawIdentifier.equals(WORKSPACE_LARGE)) { - View bubble = findViewById(R.id.workspace_cling_bubble); - ViewGroup.MarginLayoutParams lp = - (ViewGroup.MarginLayoutParams) bubble.getLayoutParams(); - lp.bottomMargin = grid.heightPx - cutOutBounds.top - mInsets.bottom; - bubble.requestLayout(); - } - } - - private Rect getWorkspaceCutOutBounds(DisplayMetrics metrics) { - int halfWidth = metrics.widthPixels / 2; - int halfHeight = metrics.heightPixels / 2; - int yOffset = DynamicGrid.pxFromDp(WORKSPACE_CIRCLE_Y_OFFSET_DPS, metrics); - if (mDrawIdentifier.equals(WORKSPACE_LARGE)) { - yOffset = 0; - } - int radius = DynamicGrid.pxFromDp(WORKSPACE_OUTER_CIRCLE_RADIUS_DPS, metrics); - return new Rect(halfWidth - radius, halfHeight - yOffset - radius, halfWidth + radius, - halfHeight - yOffset + radius); - } - - void show(boolean animate, int duration) { - setVisibility(View.VISIBLE); - setLayerType(View.LAYER_TYPE_HARDWARE, null); - if (mDrawIdentifier.equals(WORKSPACE_PORTRAIT) || - mDrawIdentifier.equals(WORKSPACE_LANDSCAPE) || - mDrawIdentifier.equals(WORKSPACE_LARGE) || - mDrawIdentifier.equals(WORKSPACE_CUSTOM) || - mDrawIdentifier.equals(MIGRATION_WORKSPACE_PORTRAIT) || - mDrawIdentifier.equals(MIGRATION_WORKSPACE_LARGE_PORTRAIT) || - mDrawIdentifier.equals(MIGRATION_WORKSPACE_LANDSCAPE)) { - View content = getContent(); - content.setAlpha(0f); - content.animate() - .alpha(1f) - .setDuration(duration) - .setListener(null) - .start(); - setAlpha(1f); - } else { - if (animate) { - buildLayer(); - setAlpha(0f); - animate() - .alpha(1f) - .setInterpolator(new AccelerateInterpolator()) - .setDuration(duration) - .setListener(null) - .start(); - } else { - setAlpha(1f); - } - } - - // Show the scrim if necessary - if (mScrimView != null) { - mScrimView.setVisibility(View.VISIBLE); - mScrimView.setAlpha(0f); - mScrimView.animate() - .alpha(1f) - .setDuration(duration) - .setListener(null) - .start(); - } - - setFocusableInTouchMode(true); - post(new Runnable() { - public void run() { - setFocusable(true); - requestFocus(); - } - }); - } - - void hide(final int duration, final Runnable postCb) { - if (mDrawIdentifier.equals(FIRST_RUN_PORTRAIT) || - mDrawIdentifier.equals(FIRST_RUN_LANDSCAPE) || - mDrawIdentifier.equals(MIGRATION_PORTRAIT) || - mDrawIdentifier.equals(MIGRATION_LANDSCAPE)) { - View content = getContent(); - content.animate() - .alpha(0f) - .setDuration(duration) - .setListener(new AnimatorListenerAdapter() { - public void onAnimationEnd(Animator animation) { - // We are about to trigger the workspace cling, so don't do anything else - setVisibility(View.GONE); - postCb.run(); - }; - }) - .start(); - } else { - animate() - .alpha(0f) - .setDuration(duration) - .setListener(new AnimatorListenerAdapter() { - public void onAnimationEnd(Animator animation) { - // We are about to trigger the workspace cling, so don't do anything else - setVisibility(View.GONE); - postCb.run(); - }; - }) - .start(); - } - - // Show the scrim if necessary - if (mScrimView != null) { - mScrimView.animate() - .alpha(0f) - .setDuration(duration) - .setListener(new AnimatorListenerAdapter() { - public void onAnimationEnd(Animator animation) { - mScrimView.setVisibility(View.GONE); - }; - }) - .start(); - } - } - - void cleanup() { - mBackground = null; - mIsInitialized = false; - } - - void bringScrimToFront() { - if (mScrimView != null) { - mScrimView.bringToFront(); - } - } - - @Override - public void setInsets(Rect insets) { - mInsets.set(insets); - setPadding(insets.left, insets.top, insets.right, insets.bottom); - } - - View getContent() { - return findViewById(R.id.content); - } - - String getDrawIdentifier() { - return mDrawIdentifier; - } - - @Override - public View focusSearch(int direction) { - return this.focusSearch(this, direction); - } - - @Override - public View focusSearch(View focused, int direction) { - return FocusFinder.getInstance().findNextFocus(this, focused, direction); - } - - @Override - public boolean onHoverEvent(MotionEvent event) { - return (mDrawIdentifier.equals(WORKSPACE_PORTRAIT) - || mDrawIdentifier.equals(WORKSPACE_LANDSCAPE) - || mDrawIdentifier.equals(WORKSPACE_LARGE) - || mDrawIdentifier.equals(WORKSPACE_CUSTOM)); - } - - @Override - public boolean onTouchEvent(android.view.MotionEvent event) { - if (mDrawIdentifier.equals(FOLDER_PORTRAIT) || - mDrawIdentifier.equals(FOLDER_LANDSCAPE) || - mDrawIdentifier.equals(FOLDER_LARGE)) { - Folder f = mLauncher.getWorkspace().getOpenFolder(); - if (f != null) { - Rect r = new Rect(); - f.getHitRect(r); - if (r.contains((int) event.getX(), (int) event.getY())) { - return false; - } - } - } - return super.onTouchEvent(event); - }; - - @Override - public boolean onTouch(View v, MotionEvent ev) { - if (ev.getAction() == MotionEvent.ACTION_DOWN) { - mTouchDownPt[0] = (int) ev.getX(); - mTouchDownPt[1] = (int) ev.getY(); - } - return false; - } - - @Override - public void onClick(View v) { - if (mDrawIdentifier.equals(WORKSPACE_PORTRAIT) || - mDrawIdentifier.equals(WORKSPACE_LANDSCAPE) || - mDrawIdentifier.equals(WORKSPACE_LARGE)) { - if (mFocusedHotseatAppBounds != null && - mFocusedHotseatAppBounds.contains(mTouchDownPt[0], mTouchDownPt[1])) { - // Launch the activity that is being highlighted - Intent intent = new Intent(Intent.ACTION_MAIN); - intent.setComponent(mFocusedHotseatAppComponent); - intent.addCategory(Intent.CATEGORY_LAUNCHER); - mLauncher.startActivity(intent, null); - mLauncher.getLauncherClings().dismissWorkspaceCling(this); - } - } - } - - @Override - public boolean onLongClick(View v) { - if (mDrawIdentifier.equals(WORKSPACE_PORTRAIT) || - mDrawIdentifier.equals(WORKSPACE_LANDSCAPE) || - mDrawIdentifier.equals(WORKSPACE_LARGE)) { - mLauncher.getLauncherClings().dismissWorkspaceCling(null); - return true; - } else if (mDrawIdentifier.equals(MIGRATION_WORKSPACE_PORTRAIT) || - mDrawIdentifier.equals(MIGRATION_WORKSPACE_LARGE_PORTRAIT) || - mDrawIdentifier.equals(MIGRATION_WORKSPACE_LANDSCAPE)) { - mLauncher.getLauncherClings().dismissMigrationWorkspaceCling(null); - return true; - } - return false; - } - - @Override - protected void dispatchDraw(Canvas canvas) { - if (mIsInitialized) { - canvas.save(); - - // Get the page indicator bounds - LauncherAppState app = LauncherAppState.getInstance(); - DeviceProfile grid = app.getDynamicGrid().getDeviceProfile(); - Rect pageIndicatorBounds = grid.getWorkspacePageIndicatorBounds(mInsets); - - // Get the background override if there is one - if (mBackground == null) { - if (mDrawIdentifier.equals(WORKSPACE_CUSTOM)) { - mBackground = getResources().getDrawable(R.drawable.bg_cling5); - } - } - // Draw the background - Bitmap eraseBg = null; - Canvas eraseCanvas = null; - if (mScrimView != null) { - // Skip drawing the background - mScrimView.setBackgroundColor(mBackgroundColor); - } else if (mBackground != null) { - mBackground.setBounds(0, 0, getMeasuredWidth(), getMeasuredHeight()); - mBackground.draw(canvas); - } else if (mDrawIdentifier.equals(WORKSPACE_PORTRAIT) || - mDrawIdentifier.equals(WORKSPACE_LANDSCAPE) || - mDrawIdentifier.equals(WORKSPACE_LARGE) || - mDrawIdentifier.equals(MIGRATION_WORKSPACE_PORTRAIT) || - mDrawIdentifier.equals(MIGRATION_WORKSPACE_LARGE_PORTRAIT) || - mDrawIdentifier.equals(MIGRATION_WORKSPACE_LANDSCAPE)) { - // Initialize the draw buffer (to allow punching through) - eraseBg = Bitmap.createBitmap(getMeasuredWidth(), getMeasuredHeight(), - Bitmap.Config.ARGB_8888); - eraseCanvas = new Canvas(eraseBg); - eraseCanvas.drawColor(mBackgroundColor); - } else { - canvas.drawColor(mBackgroundColor); - } - - // Draw everything else - DisplayMetrics metrics = new DisplayMetrics(); - mLauncher.getWindowManager().getDefaultDisplay().getMetrics(metrics); - float alpha = getAlpha(); - View content = getContent(); - if (content != null) { - alpha *= content.getAlpha(); - } - if (mDrawIdentifier.equals(FIRST_RUN_PORTRAIT) || - mDrawIdentifier.equals(FIRST_RUN_LANDSCAPE)) { - // Draw the circle - View bubbleContent = findViewById(R.id.bubble_content); - Rect bubbleRect = new Rect(); - bubbleContent.getGlobalVisibleRect(bubbleRect); - mBubblePaint.setAlpha((int) (255 * alpha)); - float buffer = DynamicGrid.pxFromDp(FIRST_RUN_CIRCLE_BUFFER_DPS, metrics); - float maxRadius = DynamicGrid.pxFromDp(FIRST_RUN_MAX_CIRCLE_RADIUS_DPS, metrics); - float radius = Math.min(maxRadius, (bubbleContent.getMeasuredWidth() + buffer) / 2); - canvas.drawCircle(metrics.widthPixels / 2, - bubbleRect.centerY(), radius, - mBubblePaint); - } else if (mDrawIdentifier.equals(WORKSPACE_PORTRAIT) || - mDrawIdentifier.equals(WORKSPACE_LANDSCAPE) || - mDrawIdentifier.equals(WORKSPACE_LARGE)) { - Rect cutOutBounds = getWorkspaceCutOutBounds(metrics); - // Draw the outer circle - mErasePaint.setAlpha(128); - eraseCanvas.drawCircle(cutOutBounds.centerX(), cutOutBounds.centerY(), - DynamicGrid.pxFromDp(WORKSPACE_OUTER_CIRCLE_RADIUS_DPS, metrics), - mErasePaint); - // Draw the inner circle - mErasePaint.setAlpha(0); - eraseCanvas.drawCircle(cutOutBounds.centerX(), cutOutBounds.centerY(), - DynamicGrid.pxFromDp(WORKSPACE_INNER_CIRCLE_RADIUS_DPS, metrics), - mErasePaint); - canvas.drawBitmap(eraseBg, 0, 0, null); - eraseCanvas.setBitmap(null); - eraseBg = null; - - // Draw the focused hotseat app icon - if (mFocusedHotseatAppBounds != null && mFocusedHotseatApp != null) { - mFocusedHotseatApp.setBounds(mFocusedHotseatAppBounds.left, - mFocusedHotseatAppBounds.top, mFocusedHotseatAppBounds.right, - mFocusedHotseatAppBounds.bottom); - mFocusedHotseatApp.setAlpha((int) (255 * alpha)); - mFocusedHotseatApp.draw(canvas); - } - } else if (mDrawIdentifier.equals(MIGRATION_WORKSPACE_PORTRAIT) || - mDrawIdentifier.equals(MIGRATION_WORKSPACE_LARGE_PORTRAIT) || - mDrawIdentifier.equals(MIGRATION_WORKSPACE_LANDSCAPE)) { - int offset = DynamicGrid.pxFromDp(WORKSPACE_CIRCLE_Y_OFFSET_DPS, metrics); - // Draw the outer circle - eraseCanvas.drawCircle(pageIndicatorBounds.centerX(), - pageIndicatorBounds.centerY(), - DynamicGrid.pxFromDp(MIGRATION_WORKSPACE_OUTER_CIRCLE_RADIUS_DPS, metrics), - mBorderPaint); - // Draw the inner circle - mErasePaint.setAlpha(0); - eraseCanvas.drawCircle(pageIndicatorBounds.centerX(), - pageIndicatorBounds.centerY(), - DynamicGrid.pxFromDp(MIGRATION_WORKSPACE_INNER_CIRCLE_RADIUS_DPS, metrics), - mErasePaint); - canvas.drawBitmap(eraseBg, 0, 0, null); - eraseCanvas.setBitmap(null); - eraseBg = null; - } - canvas.restore(); - } - - // Draw the rest of the cling - super.dispatchDraw(canvas); - }; -} diff --git a/src/com/android/launcher3/DeleteDropTarget.java b/src/com/android/launcher3/DeleteDropTarget.java index 75d906bc2..05e8906cb 100644 --- a/src/com/android/launcher3/DeleteDropTarget.java +++ b/src/com/android/launcher3/DeleteDropTarget.java @@ -30,6 +30,9 @@ import android.graphics.PointF; import android.graphics.Rect; import android.graphics.drawable.TransitionDrawable; import android.os.AsyncTask; +import android.os.Build; +import android.os.Bundle; +import android.os.UserManager; import android.util.AttributeSet; import android.view.View; import android.view.ViewConfiguration; @@ -38,6 +41,9 @@ import android.view.animation.AnimationUtils; import android.view.animation.DecelerateInterpolator; import android.view.animation.LinearInterpolator; +import com.android.launcher3.compat.LauncherAppsCompat; +import com.android.launcher3.compat.UserHandleCompat; + import java.util.List; import java.util.Set; @@ -125,11 +131,15 @@ public class DeleteDropTarget extends ButtonDropTarget { } private void setHoverColor() { - mCurrentDrawable.startTransition(mTransitionDuration); + if (mCurrentDrawable != null) { + mCurrentDrawable.startTransition(mTransitionDuration); + } setTextColor(mHoverColor); } private void resetHoverColor() { - mCurrentDrawable.resetTransition(); + if (mCurrentDrawable != null) { + mCurrentDrawable.resetTransition(); + } setTextColor(mOriginalTextColor); } @@ -184,6 +194,17 @@ public class DeleteDropTarget extends ButtonDropTarget { if (!willAcceptDrop(info) || isAllAppsWidget(source, info)) { isVisible = false; } + if (useUninstallLabel) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) { + UserManager userManager = (UserManager) + getContext().getSystemService(Context.USER_SERVICE); + Bundle restrictions = userManager.getUserRestrictions(); + if (restrictions.getBoolean(UserManager.DISALLOW_APPS_CONTROL, false) + || restrictions.getBoolean(UserManager.DISALLOW_UNINSTALL_APPS, false)) { + isVisible = false; + } + } + } if (useUninstallLabel) { setCompoundDrawablesRelativeWithIntrinsicBounds(mUninstallDrawable, null, null, null); @@ -230,8 +251,11 @@ public class DeleteDropTarget extends ButtonDropTarget { final DragLayer dragLayer = mLauncher.getDragLayer(); final Rect from = new Rect(); dragLayer.getViewRectRelativeToSelf(d.dragView, from); + + int width = mCurrentDrawable == null ? 0 : mCurrentDrawable.getIntrinsicWidth(); + int height = mCurrentDrawable == null ? 0 : mCurrentDrawable.getIntrinsicHeight(); final Rect to = getIconRect(d.dragView.getMeasuredWidth(), d.dragView.getMeasuredHeight(), - mCurrentDrawable.getIntrinsicWidth(), mCurrentDrawable.getIntrinsicHeight()); + width, height); final float scale = (float) to.width() / from.width(); mSearchDropTargetBar.deferOnDragEnd(); @@ -279,25 +303,24 @@ public class DeleteDropTarget extends ButtonDropTarget { if (isAllAppsApplication(d.dragSource, item)) { // Uninstall the application if it is being dragged from AppsCustomize AppInfo appInfo = (AppInfo) item; - mLauncher.startApplicationUninstallActivity(appInfo.componentName, appInfo.flags); + mLauncher.startApplicationUninstallActivity(appInfo.componentName, appInfo.flags, + appInfo.user); } else if (isUninstallFromWorkspace(d)) { ShortcutInfo shortcut = (ShortcutInfo) item; if (shortcut.intent != null && shortcut.intent.getComponent() != null) { final ComponentName componentName = shortcut.intent.getComponent(); final DragSource dragSource = d.dragSource; - int flags = AppInfo.initFlags( - ShortcutInfo.getPackageInfo(getContext(), componentName.getPackageName())); - mWaitingForUninstall = - mLauncher.startApplicationUninstallActivity(componentName, flags); + final UserHandleCompat user = shortcut.user; + mWaitingForUninstall = mLauncher.startApplicationUninstallActivity( + componentName, shortcut.flags, user); if (mWaitingForUninstall) { final Runnable checkIfUninstallWasSuccess = new Runnable() { @Override public void run() { mWaitingForUninstall = false; String packageName = componentName.getPackageName(); - List<ResolveInfo> activities = - AllAppsList.findActivitiesForPackage(getContext(), packageName); - boolean uninstallSuccessful = activities.size() == 0; + boolean uninstallSuccessful = !AllAppsList.packageHasActivities( + getContext(), packageName, user); if (dragSource instanceof Folder) { ((Folder) dragSource). onUninstallActivityReturned(uninstallSuccessful); @@ -324,7 +347,7 @@ public class DeleteDropTarget extends ButtonDropTarget { final LauncherAppWidgetInfo launcherAppWidgetInfo = (LauncherAppWidgetInfo) item; final LauncherAppWidgetHost appWidgetHost = mLauncher.getAppWidgetHost(); - if (appWidgetHost != null) { + if ((appWidgetHost != null) && launcherAppWidgetInfo.isWidgetIdValid()) { // Deleting an app widget ID is a void call but writes to disk before returning // to the caller... new AsyncTask<Void, Void, Void>() { @@ -353,8 +376,11 @@ public class DeleteDropTarget extends ButtonDropTarget { */ private AnimatorUpdateListener createFlingToTrashAnimatorListener(final DragLayer dragLayer, DragObject d, PointF vel, ViewConfiguration config) { + + int width = mCurrentDrawable == null ? 0 : mCurrentDrawable.getIntrinsicWidth(); + int height = mCurrentDrawable == null ? 0 : mCurrentDrawable.getIntrinsicHeight(); final Rect to = getIconRect(d.dragView.getMeasuredWidth(), d.dragView.getMeasuredHeight(), - mCurrentDrawable.getIntrinsicWidth(), mCurrentDrawable.getIntrinsicHeight()); + width, height); final Rect from = new Rect(); dragLayer.getViewRectRelativeToSelf(d.dragView, from); diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java index e67ec197a..daf5556d4 100644 --- a/src/com/android/launcher3/DeviceProfile.java +++ b/src/com/android/launcher3/DeviceProfile.java @@ -43,16 +43,18 @@ import java.util.Comparator; class DeviceProfileQuery { + DeviceProfile profile; float widthDps; float heightDps; float value; PointF dimens; - DeviceProfileQuery(float w, float h, float v) { - widthDps = w; - heightDps = h; + DeviceProfileQuery(DeviceProfile p, float v) { + widthDps = p.minWidthDps; + heightDps = p.minHeightDps; value = v; - dimens = new PointF(w, h); + dimens = new PointF(widthDps, heightDps); + profile = p; } } @@ -67,11 +69,14 @@ public class DeviceProfile { float numRows; float numColumns; float numHotseatIcons; - private float iconSize; + float iconSize; private float iconTextSize; private int iconDrawablePaddingOriginalPx; private float hotseatIconSize; + int defaultLayoutId; + int defaultNoAllAppsLayoutId; + boolean isLandscape; boolean isTablet; boolean isLargeTablet; @@ -121,13 +126,17 @@ public class DeviceProfile { int searchBarSpaceHeightPx; int searchBarHeightPx; int pageIndicatorHeightPx; + int allAppsButtonVisualSize; float dragViewScale; + int allAppsShortEdgeCount = -1; + int allAppsLongEdgeCount = -1; + private ArrayList<DeviceProfileCallbacks> mCallbacks = new ArrayList<DeviceProfileCallbacks>(); DeviceProfile(String n, float w, float h, float r, float c, - float is, float its, float hs, float his) { + float is, float its, float hs, float his, int dlId, int dnalId) { // Ensure that we have an odd number of hotseat items (since we need to place all apps) if (!LauncherAppState.isDisableAllApps() && hs % 2 == 0) { throw new RuntimeException("All Device Profiles must have an odd number of hotseat spaces"); @@ -142,6 +151,11 @@ public class DeviceProfile { iconTextSize = its; numHotseatIcons = hs; hotseatIconSize = his; + defaultLayoutId = dlId; + defaultNoAllAppsLayoutId = dnalId; + } + + DeviceProfile() { } DeviceProfile(Context context, @@ -182,38 +196,42 @@ public class DeviceProfile { overviewModeScaleFactor = res.getInteger(R.integer.config_dynamic_grid_overview_scale_percentage) / 100f; - // Interpolate the rows + // Find the closes profile given the width/height for (DeviceProfile p : profiles) { - points.add(new DeviceProfileQuery(p.minWidthDps, p.minHeightDps, p.numRows)); + points.add(new DeviceProfileQuery(p, 0f)); } - numRows = Math.round(invDistWeightedInterpolate(minWidth, minHeight, points)); - // Interpolate the columns - points.clear(); - for (DeviceProfile p : profiles) { - points.add(new DeviceProfileQuery(p.minWidthDps, p.minHeightDps, p.numColumns)); - } - numColumns = Math.round(invDistWeightedInterpolate(minWidth, minHeight, points)); - // Interpolate the hotseat length - points.clear(); - for (DeviceProfile p : profiles) { - points.add(new DeviceProfileQuery(p.minWidthDps, p.minHeightDps, p.numHotseatIcons)); - } - numHotseatIcons = Math.round(invDistWeightedInterpolate(minWidth, minHeight, points)); + DeviceProfile closestProfile = findClosestDeviceProfile(minWidth, minHeight, points); + + // Snap to the closest row count + numRows = closestProfile.numRows; + + // Snap to the closest column count + numColumns = closestProfile.numColumns; + + // Snap to the closest hotseat size + numHotseatIcons = closestProfile.numHotseatIcons; hotseatAllAppsRank = (int) (numHotseatIcons / 2); + // Snap to the closest default layout id + defaultLayoutId = closestProfile.defaultLayoutId; + + // Snap to the closest default no all-apps layout id + defaultNoAllAppsLayoutId = closestProfile.defaultNoAllAppsLayoutId; + // Interpolate the icon size points.clear(); for (DeviceProfile p : profiles) { - points.add(new DeviceProfileQuery(p.minWidthDps, p.minHeightDps, p.iconSize)); + points.add(new DeviceProfileQuery(p, p.iconSize)); } iconSize = invDistWeightedInterpolate(minWidth, minHeight, points); + // AllApps uses the original non-scaled icon size allAppsIconSizePx = DynamicGrid.pxFromDp(iconSize, dm); // Interpolate the icon text size points.clear(); for (DeviceProfile p : profiles) { - points.add(new DeviceProfileQuery(p.minWidthDps, p.minHeightDps, p.iconTextSize)); + points.add(new DeviceProfileQuery(p, p.iconTextSize)); } iconTextSize = invDistWeightedInterpolate(minWidth, minHeight, points); iconDrawablePaddingOriginalPx = @@ -224,14 +242,56 @@ public class DeviceProfile { // Interpolate the hotseat icon size points.clear(); for (DeviceProfile p : profiles) { - points.add(new DeviceProfileQuery(p.minWidthDps, p.minHeightDps, p.hotseatIconSize)); + points.add(new DeviceProfileQuery(p, p.hotseatIconSize)); } // Hotseat hotseatIconSize = invDistWeightedInterpolate(minWidth, minHeight, points); + // If the partner customization apk contains any grid overrides, apply them + applyPartnerDeviceProfileOverrides(context, dm); + // Calculate the remaining vars updateFromConfiguration(context, res, wPx, hPx, awPx, ahPx); updateAvailableDimensions(context); + computeAllAppsButtonSize(context); + } + + /** + * Apply any Partner customization grid overrides. + * + * Currently we support: all apps row / column count. + */ + private void applyPartnerDeviceProfileOverrides(Context ctx, DisplayMetrics dm) { + Partner p = Partner.get(ctx.getPackageManager()); + if (p != null) { + DeviceProfile partnerDp = p.getDeviceProfileOverride(dm); + if (partnerDp != null) { + if (partnerDp.numRows > 0 && partnerDp.numColumns > 0) { + numRows = partnerDp.numRows; + numColumns = partnerDp.numColumns; + } + if (partnerDp.allAppsShortEdgeCount > 0 && partnerDp.allAppsLongEdgeCount > 0) { + allAppsShortEdgeCount = partnerDp.allAppsShortEdgeCount; + allAppsLongEdgeCount = partnerDp.allAppsLongEdgeCount; + } + if (partnerDp.iconSize > 0) { + iconSize = partnerDp.iconSize; + // AllApps uses the original non-scaled icon size + allAppsIconSizePx = DynamicGrid.pxFromDp(iconSize, dm); + } + } + } + } + + /** + * Determine the exact visual footprint of the all apps button, taking into account scaling + * and internal padding of the drawable. + */ + private void computeAllAppsButtonSize(Context context) { + Resources res = context.getResources(); + float padding = res.getInteger(R.integer.config_allAppsButtonPaddingPercent) / 100f; + LauncherAppState app = LauncherAppState.getInstance(); + allAppsButtonVisualSize = (int) (hotseatIconSizePx * (1 - padding)); } void addCallback(DeviceProfileCallbacks cb) { @@ -357,12 +417,17 @@ public class DeviceProfile { int maxRows = (isLandscape ? maxShortEdgeCellCount : maxLongEdgeCellCount); int maxCols = (isLandscape ? maxLongEdgeCellCount : maxShortEdgeCellCount); - allAppsNumRows = (availableHeightPx - pageIndicatorHeightPx) / - (allAppsCellHeightPx + allAppsCellPaddingPx); - allAppsNumRows = Math.max(minEdgeCellCount, Math.min(maxRows, allAppsNumRows)); - allAppsNumCols = (availableWidthPx) / - (allAppsCellWidthPx + allAppsCellPaddingPx); - allAppsNumCols = Math.max(minEdgeCellCount, Math.min(maxCols, allAppsNumCols)); + if (allAppsShortEdgeCount > 0 && allAppsLongEdgeCount > 0) { + allAppsNumRows = isLandscape ? allAppsShortEdgeCount : allAppsLongEdgeCount; + allAppsNumCols = isLandscape ? allAppsLongEdgeCount : allAppsShortEdgeCount; + } else { + allAppsNumRows = (availableHeightPx - pageIndicatorHeightPx) / + (allAppsCellHeightPx + allAppsCellPaddingPx); + allAppsNumRows = Math.max(minEdgeCellCount, Math.min(maxRows, allAppsNumRows)); + allAppsNumCols = (availableWidthPx) / + (allAppsCellWidthPx + allAppsCellPaddingPx); + allAppsNumCols = Math.max(minEdgeCellCount, Math.min(maxCols, allAppsNumCols)); + } } void updateFromConfiguration(Context context, Resources resources, int wPx, int hPx, @@ -398,14 +463,18 @@ public class DeviceProfile { return (float) (1f / Math.pow(d, pow)); } - private float invDistWeightedInterpolate(float width, float height, - ArrayList<DeviceProfileQuery> points) { - float sum = 0; - float weights = 0; - float pow = 5; - float kNearestNeighbors = 3; + /** Returns the closest device profile given the width and height and a list of profiles */ + private DeviceProfile findClosestDeviceProfile(float width, float height, + ArrayList<DeviceProfileQuery> points) { + return findClosestDeviceProfiles(width, height, points).get(0).profile; + } + + /** Returns the closest device profiles ordered by closeness to the specified width and height */ + private ArrayList<DeviceProfileQuery> findClosestDeviceProfiles(float width, float height, + ArrayList<DeviceProfileQuery> points) { final PointF xy = new PointF(width, height); + // Sort the profiles by their closeness to the dimensions ArrayList<DeviceProfileQuery> pointsByNearness = points; Collections.sort(pointsByNearness, new Comparator<DeviceProfileQuery>() { public int compare(DeviceProfileQuery a, DeviceProfileQuery b) { @@ -413,6 +482,20 @@ public class DeviceProfile { } }); + return pointsByNearness; + } + + private float invDistWeightedInterpolate(float width, float height, + ArrayList<DeviceProfileQuery> points) { + float sum = 0; + float weights = 0; + float pow = 5; + float kNearestNeighbors = 3; + final PointF xy = new PointF(width, height); + + ArrayList<DeviceProfileQuery> pointsByNearness = findClosestDeviceProfiles(width, height, + points); + for (int i = 0; i < pointsByNearness.size(); ++i) { DeviceProfileQuery p = pointsByNearness.get(i); if (i < kNearestNeighbors) { @@ -739,15 +822,19 @@ public class DeviceProfile { (allAppsIconSizePx / DynamicGrid.DEFAULT_ICON_SIZE_PX))); pageIndicator = host.findViewById(R.id.apps_customize_page_indicator); if (pageIndicator != null) { - lp = (FrameLayout.LayoutParams) pageIndicator.getLayoutParams(); - lp.gravity = Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM; - lp.width = LayoutParams.WRAP_CONTENT; - lp.height = pageIndicatorHeight; - pageIndicator.setLayoutParams(lp); + LinearLayout.LayoutParams lllp = (LinearLayout.LayoutParams) pageIndicator.getLayoutParams(); + lllp.width = LayoutParams.WRAP_CONTENT; + lllp.height = pageIndicatorHeight; + pageIndicator.setLayoutParams(lllp); } AppsCustomizePagedView pagedView = (AppsCustomizePagedView) host.findViewById(R.id.apps_customize_pane_content); + + FrameLayout fakePageContainer = (FrameLayout) + host.findViewById(R.id.fake_page_container); + FrameLayout fakePage = (FrameLayout) host.findViewById(R.id.fake_page); + padding = new Rect(); if (pagedView != null) { // Constrain the dimensions of all apps so that it does not span the full width @@ -763,11 +850,24 @@ public class DeviceProfile { if ((isTablet() || isLandscape) && gridPaddingLR > (allAppsCellWidthPx / 4)) { padding.left = padding.right = gridPaddingLR; } + // The icons are centered, so we can't just offset by the page indicator height // because the empty space will actually be pageIndicatorHeight + paddingTB padding.bottom = Math.max(0, pageIndicatorHeight - paddingTB); - pagedView.setAllAppsPadding(padding); + pagedView.setWidgetsPageIndicatorPadding(pageIndicatorHeight); + fakePage.setBackground(res.getDrawable(R.drawable.quantum_panel)); + + // Horizontal padding for the whole paged view + int pagedFixedViewPadding = + res.getDimensionPixelSize(R.dimen.apps_customize_horizontal_padding); + + padding.left += pagedFixedViewPadding; + padding.right += pagedFixedViewPadding; + + pagedView.setPadding(padding.left, padding.top, padding.right, padding.bottom); + fakePageContainer.setPadding(padding.left, padding.top, padding.right, padding.bottom); + } } diff --git a/src/com/android/launcher3/DragController.java b/src/com/android/launcher3/DragController.java index 4c3ea2a0a..6d0a2be63 100644 --- a/src/com/android/launcher3/DragController.java +++ b/src/com/android/launcher3/DragController.java @@ -329,8 +329,8 @@ public class DragController { if (dragInfo != null && dragInfo.intent != null && info != null) { ComponentName cn = dragInfo.intent.getComponent(); - boolean isSameComponent = cn.equals(info.componentName) || - packageNames.contains(cn.getPackageName()); + boolean isSameComponent = cn != null && (cn.equals(info.componentName) || + packageNames.contains(cn.getPackageName())); if (isSameComponent) { cancelDrag(); return; diff --git a/src/com/android/launcher3/DragLayer.java b/src/com/android/launcher3/DragLayer.java index 862ceca28..a8a61ea89 100644 --- a/src/com/android/launcher3/DragLayer.java +++ b/src/com/android/launcher3/DragLayer.java @@ -73,7 +73,21 @@ public class DragLayer extends FrameLayout implements ViewGroup.OnHierarchyChang private final Rect mInsets = new Rect(); - private int mDragViewIndex; + private View mOverlayView; + private int mTopViewIndex; + private int mChildCountOnLastUpdate = -1; + + // Darkening scrim + private Drawable mBackground; + private float mBackgroundAlpha = 0; + + // Related to adjacent page hints + private boolean mInScrollArea; + private boolean mShowPageHints; + private Drawable mLeftHoverDrawable; + private Drawable mRightHoverDrawable; + private Drawable mLeftHoverDrawableActive; + private Drawable mRightHoverDrawableActive; /** * Used to create a new DragLayer from XML. @@ -89,8 +103,12 @@ public class DragLayer extends FrameLayout implements ViewGroup.OnHierarchyChang setChildrenDrawingOrderEnabled(true); setOnHierarchyChangeListener(this); - mLeftHoverDrawable = getResources().getDrawable(R.drawable.page_hover_left_holo); - mRightHoverDrawable = getResources().getDrawable(R.drawable.page_hover_right_holo); + final Resources res = getResources(); + mLeftHoverDrawable = res.getDrawable(R.drawable.page_hover_left); + mRightHoverDrawable = res.getDrawable(R.drawable.page_hover_right); + mLeftHoverDrawableActive = res.getDrawable(R.drawable.page_hover_left_active); + mRightHoverDrawableActive = res.getDrawable(R.drawable.page_hover_right_active); + mBackground = res.getDrawable(R.drawable.apps_customize_bg); } public void setup(Launcher launcher, DragController controller) { @@ -114,12 +132,30 @@ public class DragLayer extends FrameLayout implements ViewGroup.OnHierarchyChang return true; // I'll take it from here } + Rect getInsets() { + return mInsets; + } + @Override public void addView(View child, int index, android.view.ViewGroup.LayoutParams params) { super.addView(child, index, params); setInsets(child, mInsets, new Rect()); } + public void showOverlayView(View overlayView) { + LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); + mOverlayView = overlayView; + addView(overlayView, lp); + + // ensure that the overlay view stays on top. we can't use drawing order for this + // because in API level 16 touch dispatch doesn't respect drawing order. + mOverlayView.bringToFront(); + } + + public void dismissOverlayView() { + removeView(mOverlayView); + } + private void setInsets(View child, Rect newInsets, Rect oldInsets) { final FrameLayout.LayoutParams flp = (FrameLayout.LayoutParams) child.getLayoutParams(); if (child instanceof Insettable) { @@ -168,8 +204,7 @@ public class DragLayer extends FrameLayout implements ViewGroup.OnHierarchyChang } Folder currentFolder = mLauncher.getWorkspace().getOpenFolder(); - if (currentFolder != null && !mLauncher.getLauncherClings().isFolderClingVisible() && - intercept) { + if (currentFolder != null && intercept) { if (currentFolder.isEditingName()) { if (!isEventOverFolderTextRegion(currentFolder, ev)) { currentFolder.dismissEditingName(); @@ -544,6 +579,10 @@ public class DragLayer extends FrameLayout implements ViewGroup.OnHierarchyChang // the drag view about the scaled child view. toY += Math.round(toScale * tv.getPaddingTop()); toY -= dragView.getMeasuredHeight() * (1 - toScale) / 2; + if (dragView.getDragVisualizeOffset() != null) { + toY -= Math.round(toScale * dragView.getDragVisualizeOffset().y); + } + toX -= (dragView.getMeasuredWidth() - Math.round(scale * child.getMeasuredWidth())) / 2; } else if (child instanceof FolderIcon) { // Account for holographic blur padding on the drag view @@ -762,6 +801,11 @@ public class DragLayer extends FrameLayout implements ViewGroup.OnHierarchyChang @Override public void onChildViewAdded(View parent, View child) { + if (mOverlayView != null) { + // ensure that the overlay view stays on top. we can't use drawing order for this + // because in API level 16 touch dispatch doesn't respect drawing order. + mOverlayView.bringToFront(); + } updateChildIndices(); } @@ -770,34 +814,54 @@ public class DragLayer extends FrameLayout implements ViewGroup.OnHierarchyChang updateChildIndices(); } + @Override + public void bringChildToFront(View child) { + super.bringChildToFront(child); + if (child != mOverlayView && mOverlayView != null) { + // ensure that the overlay view stays on top. we can't use drawing order for this + // because in API level 16 touch dispatch doesn't respect drawing order. + mOverlayView.bringToFront(); + } + updateChildIndices(); + } + private void updateChildIndices() { - mDragViewIndex = -1; + mTopViewIndex = -1; int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { if (getChildAt(i) instanceof DragView) { - mDragViewIndex = i; + mTopViewIndex = i; } } + mChildCountOnLastUpdate = childCount; } @Override protected int getChildDrawingOrder(int childCount, int i) { - if (mDragViewIndex == -1) { + if (mChildCountOnLastUpdate != childCount) { + // between platform versions 17 and 18, behavior for onChildViewRemoved / Added changed. + // Pre-18, the child was not added / removed by the time of those callbacks. We need to + // force update our representation of things here to avoid crashing on pre-18 devices + // in certain instances. + updateChildIndices(); + } + + // i represents the current draw iteration + if (mTopViewIndex == -1) { + // in general we do nothing return i; - } else if (i == mDragViewIndex) { - return getChildCount()-1; - } else if (i < mDragViewIndex) { + } else if (i == childCount - 1) { + // if we have a top index, we return it when drawing last item (highest z-order) + return mTopViewIndex; + } else if (i < mTopViewIndex) { return i; } else { - // i > mDragViewIndex - return i-1; + // for indexes greater than the top index, we fetch one item above to shift for the + // displacement of the top index + return i + 1; } } - private boolean mInScrollArea; - private Drawable mLeftHoverDrawable; - private Drawable mRightHoverDrawable; - void onEnterScrollArea(int direction) { mInScrollArea = true; invalidate(); @@ -808,6 +872,16 @@ public class DragLayer extends FrameLayout implements ViewGroup.OnHierarchyChang invalidate(); } + void showPageHints() { + mShowPageHints = true; + invalidate(); + } + + void hidePageHints() { + mShowPageHints = false; + invalidate(); + } + /** * Note: this is a reimplementation of View.isLayoutRtl() since that is currently hidden api. */ @@ -817,31 +891,68 @@ public class DragLayer extends FrameLayout implements ViewGroup.OnHierarchyChang @Override protected void dispatchDraw(Canvas canvas) { + // Draw the background gradient below children. + if (mBackground != null && mBackgroundAlpha > 0.0f) { + int alpha = (int) (mBackgroundAlpha * 255); + mBackground.setAlpha(alpha); + mBackground.setBounds(0, 0, getMeasuredWidth(), getMeasuredHeight()); + mBackground.draw(canvas); + } + super.dispatchDraw(canvas); + } - if (mInScrollArea && !LauncherAppState.getInstance().isScreenLarge()) { + private void drawPageHints(Canvas canvas) { + if (mShowPageHints) { Workspace workspace = mLauncher.getWorkspace(); int width = getMeasuredWidth(); Rect childRect = new Rect(); - getDescendantRectRelativeToSelf(workspace.getChildAt(0), childRect); + getDescendantRectRelativeToSelf(workspace.getChildAt(workspace.getChildCount() - 1), + childRect); int page = workspace.getNextPage(); final boolean isRtl = isLayoutRtl(); CellLayout leftPage = (CellLayout) workspace.getChildAt(isRtl ? page + 1 : page - 1); CellLayout rightPage = (CellLayout) workspace.getChildAt(isRtl ? page - 1 : page + 1); - if (leftPage != null && leftPage.getIsDragOverlapping()) { - mLeftHoverDrawable.setBounds(0, childRect.top, - mLeftHoverDrawable.getIntrinsicWidth(), childRect.bottom); - mLeftHoverDrawable.draw(canvas); - } else if (rightPage != null && rightPage.getIsDragOverlapping()) { - mRightHoverDrawable.setBounds(width - mRightHoverDrawable.getIntrinsicWidth(), + if (leftPage != null && leftPage.isDragTarget()) { + Drawable left = mInScrollArea && leftPage.getIsDragOverlapping() ? + mLeftHoverDrawableActive : mLeftHoverDrawable; + left.setBounds(0, childRect.top, + left.getIntrinsicWidth(), childRect.bottom); + left.draw(canvas); + } + if (rightPage != null && rightPage.isDragTarget()) { + Drawable right = mInScrollArea && rightPage.getIsDragOverlapping() ? + mRightHoverDrawableActive : mRightHoverDrawable; + right.setBounds(width - right.getIntrinsicWidth(), childRect.top, width, childRect.bottom); - mRightHoverDrawable.draw(canvas); + right.draw(canvas); } } } + protected boolean drawChild(Canvas canvas, View child, long drawingTime) { + boolean ret = super.drawChild(canvas, child, drawingTime); + + // We want to draw the page hints above the workspace, but below the drag view. + if (child instanceof Workspace) { + drawPageHints(canvas); + } + return ret; + } + + public void setBackgroundAlpha(float alpha) { + if (alpha != mBackgroundAlpha) { + mBackgroundAlpha = alpha; + invalidate(); + } + } + + public float getBackgroundAlpha() { + return mBackgroundAlpha; + } + public void setTouchCompleteListener(TouchCompleteListener listener) { mTouchCompleteListener = listener; } diff --git a/src/com/android/launcher3/DynamicGrid.java b/src/com/android/launcher3/DynamicGrid.java index 447bb1cd8..94a07d706 100644 --- a/src/com/android/launcher3/DynamicGrid.java +++ b/src/com/android/launcher3/DynamicGrid.java @@ -60,36 +60,41 @@ public class DynamicGrid { DEFAULT_ICON_SIZE_PX = pxFromDp(DEFAULT_ICON_SIZE_DP, dm); // Our phone profiles include the bar sizes in each orientation deviceProfiles.add(new DeviceProfile("Super Short Stubby", - 255, 300, 2, 3, 48, 13, (hasAA ? 5 : 5), 48)); + 255, 300, 2, 3, 48, 13, (hasAA ? 3 : 5), 48, R.xml.default_workspace_4x4, + R.xml.default_workspace_4x4_no_all_apps)); deviceProfiles.add(new DeviceProfile("Shorter Stubby", - 255, 400, 3, 3, 48, 13, (hasAA ? 5 : 5), 48)); + 255, 400, 3, 3, 48, 13, (hasAA ? 3 : 5), 48, R.xml.default_workspace_4x4, + R.xml.default_workspace_4x4_no_all_apps)); deviceProfiles.add(new DeviceProfile("Short Stubby", - 275, 420, 3, 4, 48, 13, (hasAA ? 5 : 5), 48)); + 275, 420, 3, 4, 48, 13, (hasAA ? 5 : 5), 48, R.xml.default_workspace_4x4, + R.xml.default_workspace_4x4_no_all_apps)); deviceProfiles.add(new DeviceProfile("Stubby", - 255, 450, 3, 4, 48, 13, (hasAA ? 5 : 5), 48)); + 255, 450, 3, 4, 48, 13, (hasAA ? 5 : 5), 48, R.xml.default_workspace_4x4, + R.xml.default_workspace_4x4_no_all_apps)); deviceProfiles.add(new DeviceProfile("Nexus S", - 296, 491.33f, 4, 4, 48, 13, (hasAA ? 5 : 5), 48)); + 296, 491.33f, 4, 4, 48, 13, (hasAA ? 5 : 5), 48, R.xml.default_workspace_4x4, + R.xml.default_workspace_4x4_no_all_apps)); deviceProfiles.add(new DeviceProfile("Nexus 4", - 335, 567, 4, 4, DEFAULT_ICON_SIZE_DP, 13, (hasAA ? 5 : 5), 56)); + 335, 567, 4, 4, DEFAULT_ICON_SIZE_DP, 13, (hasAA ? 5 : 5), 56, R.xml.default_workspace_4x4, + R.xml.default_workspace_4x4_no_all_apps)); deviceProfiles.add(new DeviceProfile("Nexus 5", - 359, 567, 4, 4, DEFAULT_ICON_SIZE_DP, 13, (hasAA ? 5 : 5), 56)); + 359, 567, 4, 4, DEFAULT_ICON_SIZE_DP, 13, (hasAA ? 5 : 5), 56, R.xml.default_workspace_4x4, + R.xml.default_workspace_4x4_no_all_apps)); deviceProfiles.add(new DeviceProfile("Large Phone", - 406, 694, 5, 5, 64, 14.4f, 5, 56)); + 406, 694, 5, 5, 64, 14.4f, 5, 56, R.xml.default_workspace_5x5, + R.xml.default_workspace_5x5_no_all_apps)); // The tablet profile is odd in that the landscape orientation // also includes the nav bar on the side deviceProfiles.add(new DeviceProfile("Nexus 7", - 575, 904, 5, 6, 72, 14.4f, 7, 60)); + 575, 904, 5, 6, 72, 14.4f, 7, 60, R.xml.default_workspace_5x6, + R.xml.default_workspace_5x6_no_all_apps)); // Larger tablet profiles always have system bars on the top & bottom deviceProfiles.add(new DeviceProfile("Nexus 10", - 727, 1207, 5, 6, 76, 14.4f, 7, 64)); - /* - deviceProfiles.add(new DeviceProfile("Nexus 7", - 600, 960, 5, 5, 72, 14.4f, 5, 60)); - deviceProfiles.add(new DeviceProfile("Nexus 10", - 800, 1280, 5, 5, 80, 14.4f, (hasAA ? 7 : 6), 64)); - */ + 727, 1207, 5, 6, 76, 14.4f, 7, 64, R.xml.default_workspace_5x6, + R.xml.default_workspace_5x6_no_all_apps)); deviceProfiles.add(new DeviceProfile("20-inch Tablet", - 1527, 2527, 7, 7, 100, 20, 7, 72)); + 1527, 2527, 7, 7, 100, 20, 7, 72, R.xml.default_workspace_4x4, + R.xml.default_workspace_4x4_no_all_apps)); mMinWidth = dpiFromPx(minWidthPx, dm); mMinHeight = dpiFromPx(minHeightPx, dm); mProfile = new DeviceProfile(context, deviceProfiles, diff --git a/src/com/android/launcher3/FastBitmapDrawable.java b/src/com/android/launcher3/FastBitmapDrawable.java index 85e90202b..ff02bbbc3 100644 --- a/src/com/android/launcher3/FastBitmapDrawable.java +++ b/src/com/android/launcher3/FastBitmapDrawable.java @@ -16,18 +16,61 @@ package com.android.launcher3; +import android.animation.ObjectAnimator; +import android.animation.TimeInterpolator; import android.graphics.Bitmap; import android.graphics.Canvas; +import android.graphics.Color; import android.graphics.ColorFilter; +import android.graphics.ColorMatrix; +import android.graphics.ColorMatrixColorFilter; import android.graphics.Paint; import android.graphics.PixelFormat; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; import android.graphics.Rect; import android.graphics.drawable.Drawable; +import android.util.SparseArray; class FastBitmapDrawable extends Drawable { - private Bitmap mBitmap; - private int mAlpha; + + static final TimeInterpolator CLICK_FEEDBACK_INTERPOLATOR = new TimeInterpolator() { + + @Override + public float getInterpolation(float input) { + if (input < 0.05f) { + return input / 0.05f; + } else if (input < 0.3f){ + return 1; + } else { + return (1 - input) / 0.7f; + } + } + }; + static final long CLICK_FEEDBACK_DURATION = 2000; + + private static final int PRESSED_BRIGHTNESS = 100; + private static ColorMatrix sGhostModeMatrix; + private static final ColorMatrix sTempMatrix = new ColorMatrix(); + + /** + * Store the brightness colors filters to optimize animations during icon press. This + * only works for non-ghost-mode icons. + */ + private static final SparseArray<ColorFilter> sCachedBrightnessFilter = + new SparseArray<ColorFilter>(); + + private static final int GHOST_MODE_MIN_COLOR_RANGE = 130; + private final Paint mPaint = new Paint(Paint.FILTER_BITMAP_FLAG); + private final Bitmap mBitmap; + private int mAlpha; + + private int mBrightness = 0; + private boolean mGhostModeEnabled = false; + + private boolean mPressed = false; + private ObjectAnimator mPressedAnimator; FastBitmapDrawable(Bitmap b) { mAlpha = 255; @@ -44,7 +87,7 @@ class FastBitmapDrawable extends Drawable { @Override public void setColorFilter(ColorFilter cf) { - mPaint.setColorFilter(cf); + // No op } @Override @@ -58,6 +101,7 @@ class FastBitmapDrawable extends Drawable { mPaint.setAlpha(alpha); } + @Override public void setFilterBitmap(boolean filterBitmap) { mPaint.setFilterBitmap(filterBitmap); mPaint.setAntiAlias(filterBitmap); @@ -69,12 +113,12 @@ class FastBitmapDrawable extends Drawable { @Override public int getIntrinsicWidth() { - return getBounds().width(); + return mBitmap.getWidth(); } @Override public int getIntrinsicHeight() { - return getBounds().height(); + return mBitmap.getHeight(); } @Override @@ -90,4 +134,98 @@ class FastBitmapDrawable extends Drawable { public Bitmap getBitmap() { return mBitmap; } + + /** + * When enabled, the icon is grayed out and the contrast is increased to give it a 'ghost' + * appearance. + */ + public void setGhostModeEnabled(boolean enabled) { + if (mGhostModeEnabled != enabled) { + mGhostModeEnabled = enabled; + updateFilter(); + } + } + + public void setPressed(boolean pressed) { + if (mPressed != pressed) { + mPressed = pressed; + if (mPressed) { + mPressedAnimator = ObjectAnimator + .ofInt(this, "brightness", PRESSED_BRIGHTNESS) + .setDuration(CLICK_FEEDBACK_DURATION); + mPressedAnimator.setInterpolator(CLICK_FEEDBACK_INTERPOLATOR); + mPressedAnimator.start(); + } else if (mPressedAnimator != null) { + mPressedAnimator.cancel(); + setBrightness(0); + } + } + invalidateSelf(); + } + + public boolean isGhostModeEnabled() { + return mGhostModeEnabled; + } + + public int getBrightness() { + return mBrightness; + } + + public void setBrightness(int brightness) { + if (mBrightness != brightness) { + mBrightness = brightness; + updateFilter(); + invalidateSelf(); + } + } + + private void updateFilter() { + if (mGhostModeEnabled) { + if (sGhostModeMatrix == null) { + sGhostModeMatrix = new ColorMatrix(); + sGhostModeMatrix.setSaturation(0); + + // For ghost mode, set the color range to [GHOST_MODE_MIN_COLOR_RANGE, 255] + float range = (255 - GHOST_MODE_MIN_COLOR_RANGE) / 255.0f; + sTempMatrix.set(new float[] { + range, 0, 0, 0, GHOST_MODE_MIN_COLOR_RANGE, + 0, range, 0, 0, GHOST_MODE_MIN_COLOR_RANGE, + 0, 0, range, 0, GHOST_MODE_MIN_COLOR_RANGE, + 0, 0, 0, 1, 0 }); + sGhostModeMatrix.preConcat(sTempMatrix); + } + + if (mBrightness == 0) { + mPaint.setColorFilter(new ColorMatrixColorFilter(sGhostModeMatrix)); + } else { + setBrightnessMatrix(sTempMatrix, mBrightness); + sTempMatrix.postConcat(sGhostModeMatrix); + mPaint.setColorFilter(new ColorMatrixColorFilter(sTempMatrix)); + } + } else if (mBrightness != 0) { + ColorFilter filter = sCachedBrightnessFilter.get(mBrightness); + if (filter == null) { + filter = new PorterDuffColorFilter(Color.argb(mBrightness, 255, 255, 255), + PorterDuff.Mode.SRC_ATOP); + sCachedBrightnessFilter.put(mBrightness, filter); + } + mPaint.setColorFilter(filter); + } else { + mPaint.setColorFilter(null); + } + } + + private static void setBrightnessMatrix(ColorMatrix matrix, int brightness) { + // Brightness: C-new = C-old*(1-amount) + amount + float scale = 1 - brightness / 255.0f; + matrix.setScale(scale, scale, scale, 1); + float[] array = matrix.getArray(); + + // Add the amount to RGB components of the matrix, as per the above formula. + // Fifth elements in the array correspond to the constant being added to + // red, blue, green, and alpha channel respectively. + array[4] = brightness; + array[9] = brightness; + array[14] = brightness; + } } diff --git a/src/com/android/launcher3/FastBitmapView.java b/src/com/android/launcher3/FastBitmapView.java new file mode 100644 index 000000000..0937eb75e --- /dev/null +++ b/src/com/android/launcher3/FastBitmapView.java @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2014 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.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.view.View; + +public class FastBitmapView extends View { + + private final Paint mPaint = new Paint(Paint.FILTER_BITMAP_FLAG); + private Bitmap mBitmap; + + public FastBitmapView(Context context) { + super(context); + } + + /** + * Applies the new bitmap. + * @return true if the view was invalidated. + */ + public boolean setBitmap(Bitmap b) { + if (b != mBitmap){ + if (mBitmap != null) { + invalidate(0, 0, mBitmap.getWidth(), mBitmap.getHeight()); + } + mBitmap = b; + if (mBitmap != null) { + invalidate(0, 0, mBitmap.getWidth(), mBitmap.getHeight()); + } + return true; + } + return false; + } + + @Override + protected void onDraw(Canvas canvas) { + if (mBitmap != null) { + canvas.drawBitmap(mBitmap, 0, 0, mPaint); + } + } +} diff --git a/src/com/android/launcher3/FocusHelper.java b/src/com/android/launcher3/FocusHelper.java index bb62bac65..d529b3901 100644 --- a/src/com/android/launcher3/FocusHelper.java +++ b/src/com/android/launcher3/FocusHelper.java @@ -17,13 +17,13 @@ package com.android.launcher3; import android.content.res.Configuration; +import android.util.Log; import android.view.KeyEvent; +import android.view.SoundEffectConstants; import android.view.View; import android.view.ViewGroup; import android.view.ViewParent; import android.widget.ScrollView; -import android.widget.TabHost; -import android.widget.TabWidget; import java.util.ArrayList; import java.util.Collections; @@ -57,61 +57,16 @@ class HotseatIconKeyEventListener implements View.OnKeyListener { } } -/** - * A keyboard listener we set on the last tab button in AppsCustomize to jump to then - * market icon and vice versa. - */ -class AppsCustomizeTabKeyEventListener implements View.OnKeyListener { - public boolean onKey(View v, int keyCode, KeyEvent event) { - return FocusHelper.handleAppsCustomizeTabKeyEvent(v, keyCode, event); - } -} - public class FocusHelper { /** * Private helper to get the parent TabHost in the view hiearchy. */ - private static TabHost findTabHostParent(View v) { + private static AppsCustomizeTabHost findTabHostParent(View v) { ViewParent p = v.getParent(); - while (p != null && !(p instanceof TabHost)) { + while (p != null && !(p instanceof AppsCustomizeTabHost)) { p = p.getParent(); } - return (TabHost) p; - } - - /** - * Handles key events in a AppsCustomize tab between the last tab view and the shop button. - */ - static boolean handleAppsCustomizeTabKeyEvent(View v, int keyCode, KeyEvent e) { - final TabHost tabHost = findTabHostParent(v); - final ViewGroup contents = tabHost.getTabContentView(); - final View shop = tabHost.findViewById(R.id.market_button); - - final int action = e.getAction(); - final boolean handleKeyEvent = (action != KeyEvent.ACTION_UP); - boolean wasHandled = false; - switch (keyCode) { - case KeyEvent.KEYCODE_DPAD_RIGHT: - if (handleKeyEvent) { - // Select the shop button if we aren't on it - if (v != shop) { - shop.requestFocus(); - } - } - wasHandled = true; - break; - case KeyEvent.KEYCODE_DPAD_DOWN: - if (handleKeyEvent) { - // Select the content view (down is handled by the tab key handler otherwise) - if (v == shop) { - contents.requestFocus(); - wasHandled = true; - } - } - break; - default: break; - } - return wasHandled; + return (AppsCustomizeTabHost) p; } /** @@ -134,8 +89,6 @@ public class FocusHelper { final PagedViewGridLayout parent = (PagedViewGridLayout) w.getParent(); final PagedView container = (PagedView) parent.getParent(); - final TabHost tabHost = findTabHostParent(container); - final TabWidget tabs = tabHost.getTabWidget(); final int widgetIndex = parent.indexOfChild(w); final int widgetCount = parent.getChildCount(); final int pageIndex = ((PagedView) container).indexToPage(container.indexOfChild(parent)); @@ -194,8 +147,6 @@ public class FocusHelper { int newWidgetIndex = ((y - 1) * cellCountX) + x; child = parent.getChildAt(newWidgetIndex); if (child != null) child.requestFocus(); - } else { - tabs.requestFocus(); } } wasHandled = true; @@ -294,8 +245,6 @@ public class FocusHelper { // Note we have an extra parent because of the // PagedViewCellLayout/PagedViewCellLayoutChildren relationship final PagedView container = (PagedView) parentLayout.getParent(); - final TabHost tabHost = findTabHostParent(container); - final TabWidget tabs = tabHost.getTabWidget(); final int iconIndex = itemContainer.indexOfChild(v); final int itemCount = itemContainer.getChildCount(); final int pageIndex = ((PagedView) container).indexToPage(container.indexOfChild(parentLayout)); @@ -317,13 +266,17 @@ public class FocusHelper { // Select the previous icon or the last icon on the previous page if (iconIndex > 0) { itemContainer.getChildAt(iconIndex - 1).requestFocus(); + v.playSoundEffect(SoundEffectConstants.NAVIGATION_LEFT); } else { if (pageIndex > 0) { newParent = getAppsCustomizePage(container, pageIndex - 1); if (newParent != null) { container.snapToPage(pageIndex - 1); child = newParent.getChildAt(newParent.getChildCount() - 1); - if (child != null) child.requestFocus(); + if (child != null) { + child.requestFocus(); + v.playSoundEffect(SoundEffectConstants.NAVIGATION_LEFT); + } } } } @@ -335,13 +288,17 @@ public class FocusHelper { // Select the next icon or the first icon on the next page if (iconIndex < (itemCount - 1)) { itemContainer.getChildAt(iconIndex + 1).requestFocus(); + v.playSoundEffect(SoundEffectConstants.NAVIGATION_RIGHT); } else { if (pageIndex < (pageCount - 1)) { newParent = getAppsCustomizePage(container, pageIndex + 1); if (newParent != null) { container.snapToPage(pageIndex + 1); child = newParent.getChildAt(0); - if (child != null) child.requestFocus(); + if (child != null) { + child.requestFocus(); + v.playSoundEffect(SoundEffectConstants.NAVIGATION_RIGHT); + } } } } @@ -354,31 +311,25 @@ public class FocusHelper { if (y > 0) { int newiconIndex = ((y - 1) * countX) + x; itemContainer.getChildAt(newiconIndex).requestFocus(); - } else { - tabs.requestFocus(); + v.playSoundEffect(SoundEffectConstants.NAVIGATION_UP); } } wasHandled = true; break; case KeyEvent.KEYCODE_DPAD_DOWN: if (handleKeyEvent) { - // Select the closest icon in the previous row, otherwise do nothing + // Select the closest icon in the next row, otherwise do nothing if (y < (countY - 1)) { int newiconIndex = Math.min(itemCount - 1, ((y + 1) * countX) + x); - itemContainer.getChildAt(newiconIndex).requestFocus(); + int newIconY = newiconIndex / countX; + if (newIconY != y) { + itemContainer.getChildAt(newiconIndex).requestFocus(); + v.playSoundEffect(SoundEffectConstants.NAVIGATION_DOWN); + } } } wasHandled = true; break; - case KeyEvent.KEYCODE_ENTER: - case KeyEvent.KEYCODE_DPAD_CENTER: - if (handleKeyEvent) { - // Simulate a click on the icon - View.OnClickListener clickListener = (View.OnClickListener) container; - clickListener.onClick(v); - } - wasHandled = true; - break; case KeyEvent.KEYCODE_PAGE_UP: if (handleKeyEvent) { // Select the first icon on the previous page, or the first icon on this page @@ -388,10 +339,14 @@ public class FocusHelper { if (newParent != null) { container.snapToPage(pageIndex - 1); child = newParent.getChildAt(0); - if (child != null) child.requestFocus(); + if (child != null) { + child.requestFocus(); + v.playSoundEffect(SoundEffectConstants.NAVIGATION_UP); + } } } else { itemContainer.getChildAt(0).requestFocus(); + v.playSoundEffect(SoundEffectConstants.NAVIGATION_UP); } } wasHandled = true; @@ -405,10 +360,14 @@ public class FocusHelper { if (newParent != null) { container.snapToPage(pageIndex + 1); child = newParent.getChildAt(0); - if (child != null) child.requestFocus(); + if (child != null) { + child.requestFocus(); + v.playSoundEffect(SoundEffectConstants.NAVIGATION_DOWN); + } } } else { itemContainer.getChildAt(itemCount - 1).requestFocus(); + v.playSoundEffect(SoundEffectConstants.NAVIGATION_DOWN); } } wasHandled = true; @@ -417,6 +376,7 @@ public class FocusHelper { if (handleKeyEvent) { // Select the first icon on this page itemContainer.getChildAt(0).requestFocus(); + v.playSoundEffect(SoundEffectConstants.NAVIGATION_UP); } wasHandled = true; break; @@ -424,6 +384,7 @@ public class FocusHelper { if (handleKeyEvent) { // Select the last icon on this page itemContainer.getChildAt(itemCount - 1).requestFocus(); + v.playSoundEffect(SoundEffectConstants.NAVIGATION_DOWN); } wasHandled = true; break; @@ -439,8 +400,8 @@ public class FocusHelper { if (!LauncherAppState.getInstance().isScreenLarge()) return false; final FocusOnlyTabWidget parent = (FocusOnlyTabWidget) v.getParent(); - final TabHost tabHost = findTabHostParent(parent); - final ViewGroup contents = tabHost.getTabContentView(); + final AppsCustomizeTabHost tabHost = findTabHostParent(parent); + final ViewGroup contents = tabHost.getContent(); final int tabCount = parent.getTabCount(); final int tabIndex = parent.getChildTabIndex(v); @@ -490,53 +451,56 @@ public class FocusHelper { * Handles key events in the workspace hotseat (bottom of the screen). */ static boolean handleHotseatButtonKeyEvent(View v, int keyCode, KeyEvent e, int orientation) { - final ViewGroup parent = (ViewGroup) v.getParent(); - final ViewGroup launcher = (ViewGroup) parent.getParent(); - final Workspace workspace = (Workspace) launcher.findViewById(R.id.workspace); - final int buttonIndex = parent.indexOfChild(v); - final int buttonCount = parent.getChildCount(); - final int pageIndex = workspace.getCurrentPage(); + ShortcutAndWidgetContainer parent = (ShortcutAndWidgetContainer) v.getParent(); + final CellLayout layout = (CellLayout) parent.getParent(); // NOTE: currently we don't special case for the phone UI in different - // orientations, even though the hotseat is on the side in landscape mode. This + // orientations, even though the hotseat is on the side in landscape mode. This // is to ensure that accessibility consistency is maintained across rotations. - final int action = e.getAction(); final boolean handleKeyEvent = (action != KeyEvent.ACTION_UP); boolean wasHandled = false; switch (keyCode) { case KeyEvent.KEYCODE_DPAD_LEFT: if (handleKeyEvent) { - // Select the previous button, otherwise snap to the previous page - if (buttonIndex > 0) { - parent.getChildAt(buttonIndex - 1).requestFocus(); - } else { - workspace.snapToPage(pageIndex - 1); + ArrayList<View> views = getCellLayoutChildrenSortedSpatially(layout, parent); + int myIndex = views.indexOf(v); + // Select the previous button, otherwise do nothing + if (myIndex > 0) { + views.get(myIndex - 1).requestFocus(); + v.playSoundEffect(SoundEffectConstants.NAVIGATION_LEFT); } } wasHandled = true; break; case KeyEvent.KEYCODE_DPAD_RIGHT: if (handleKeyEvent) { - // Select the next button, otherwise snap to the next page - if (buttonIndex < (buttonCount - 1)) { - parent.getChildAt(buttonIndex + 1).requestFocus(); - } else { - workspace.snapToPage(pageIndex + 1); + ArrayList<View> views = getCellLayoutChildrenSortedSpatially(layout, parent); + int myIndex = views.indexOf(v); + // Select the next button, otherwise do nothing + if (myIndex < views.size() - 1) { + views.get(myIndex + 1).requestFocus(); + v.playSoundEffect(SoundEffectConstants.NAVIGATION_RIGHT); } } wasHandled = true; break; case KeyEvent.KEYCODE_DPAD_UP: if (handleKeyEvent) { - // Select the first bubble text view in the current page of the workspace - final CellLayout layout = (CellLayout) workspace.getChildAt(pageIndex); - final ShortcutAndWidgetContainer children = layout.getShortcutsAndWidgets(); - final View newIcon = getIconInDirection(layout, children, -1, 1); - if (newIcon != null) { - newIcon.requestFocus(); - } else { - workspace.requestFocus(); + final Workspace workspace = (Workspace) + v.getRootView().findViewById(R.id.workspace); + if (workspace != null) { + int pageIndex = workspace.getCurrentPage(); + CellLayout topLayout = (CellLayout) workspace.getChildAt(pageIndex); + ShortcutAndWidgetContainer children = topLayout.getShortcutsAndWidgets(); + final View newIcon = getIconInDirection(layout, children, -1, 1); + // Select the first bubble text view in the current page of the workspace + if (newIcon != null) { + newIcon.requestFocus(); + v.playSoundEffect(SoundEffectConstants.NAVIGATION_UP); + } else { + workspace.requestFocus(); + } } } wasHandled = true; @@ -555,8 +519,8 @@ public class FocusHelper { */ private static ShortcutAndWidgetContainer getCellLayoutChildrenForIndex( ViewGroup container, int i) { - ViewGroup parent = (ViewGroup) container.getChildAt(i); - return (ShortcutAndWidgetContainer) parent.getChildAt(0); + CellLayout parent = (CellLayout) container.getChildAt(i); + return parent.getShortcutsAndWidgets(); } /** @@ -680,6 +644,7 @@ public class FocusHelper { View newIcon = getIconInDirection(layout, parent, v, -1); if (newIcon != null) { newIcon.requestFocus(); + v.playSoundEffect(SoundEffectConstants.NAVIGATION_LEFT); } else { if (pageIndex > 0) { parent = getCellLayoutChildrenForIndex(workspace, pageIndex - 1); @@ -691,6 +656,7 @@ public class FocusHelper { // Snap to the previous page workspace.snapToPage(pageIndex - 1); } + v.playSoundEffect(SoundEffectConstants.NAVIGATION_LEFT); } } } @@ -702,6 +668,7 @@ public class FocusHelper { View newIcon = getIconInDirection(layout, parent, v, 1); if (newIcon != null) { newIcon.requestFocus(); + v.playSoundEffect(SoundEffectConstants.NAVIGATION_RIGHT); } else { if (pageIndex < (pageCount - 1)) { parent = getCellLayoutChildrenForIndex(workspace, pageIndex + 1); @@ -712,6 +679,7 @@ public class FocusHelper { // Snap to the next page workspace.snapToPage(pageIndex + 1); } + v.playSoundEffect(SoundEffectConstants.NAVIGATION_RIGHT); } } } @@ -727,6 +695,7 @@ public class FocusHelper { } else { tabs.requestFocus(); } + v.playSoundEffect(SoundEffectConstants.NAVIGATION_UP); } break; case KeyEvent.KEYCODE_DPAD_DOWN: @@ -735,9 +704,11 @@ public class FocusHelper { View newIcon = getClosestIconOnLine(layout, parent, v, 1); if (newIcon != null) { newIcon.requestFocus(); + v.playSoundEffect(SoundEffectConstants.NAVIGATION_DOWN); wasHandled = true; } else if (hotseat != null) { hotseat.requestFocus(); + v.playSoundEffect(SoundEffectConstants.NAVIGATION_DOWN); } } break; @@ -754,10 +725,12 @@ public class FocusHelper { // Snap to the previous page workspace.snapToPage(pageIndex - 1); } + v.playSoundEffect(SoundEffectConstants.NAVIGATION_UP); } else { View newIcon = getIconInDirection(layout, parent, -1, 1); if (newIcon != null) { newIcon.requestFocus(); + v.playSoundEffect(SoundEffectConstants.NAVIGATION_UP); } } } @@ -776,11 +749,13 @@ public class FocusHelper { // Snap to the next page workspace.snapToPage(pageIndex + 1); } + v.playSoundEffect(SoundEffectConstants.NAVIGATION_DOWN); } else { View newIcon = getIconInDirection(layout, parent, parent.getChildCount(), -1); if (newIcon != null) { newIcon.requestFocus(); + v.playSoundEffect(SoundEffectConstants.NAVIGATION_DOWN); } } } @@ -792,6 +767,7 @@ public class FocusHelper { View newIcon = getIconInDirection(layout, parent, -1, 1); if (newIcon != null) { newIcon.requestFocus(); + v.playSoundEffect(SoundEffectConstants.NAVIGATION_UP); } } wasHandled = true; @@ -803,6 +779,7 @@ public class FocusHelper { parent.getChildCount(), -1); if (newIcon != null) { newIcon.requestFocus(); + v.playSoundEffect(SoundEffectConstants.NAVIGATION_DOWN); } } wasHandled = true; @@ -832,6 +809,7 @@ public class FocusHelper { View newIcon = getIconInDirection(layout, parent, v, -1); if (newIcon != null) { newIcon.requestFocus(); + v.playSoundEffect(SoundEffectConstants.NAVIGATION_LEFT); } } wasHandled = true; @@ -845,6 +823,7 @@ public class FocusHelper { } else { title.requestFocus(); } + v.playSoundEffect(SoundEffectConstants.NAVIGATION_RIGHT); } wasHandled = true; break; @@ -854,6 +833,7 @@ public class FocusHelper { View newIcon = getClosestIconOnLine(layout, parent, v, -1); if (newIcon != null) { newIcon.requestFocus(); + v.playSoundEffect(SoundEffectConstants.NAVIGATION_UP); } } wasHandled = true; @@ -867,6 +847,7 @@ public class FocusHelper { } else { title.requestFocus(); } + v.playSoundEffect(SoundEffectConstants.NAVIGATION_DOWN); } wasHandled = true; break; @@ -876,6 +857,7 @@ public class FocusHelper { View newIcon = getIconInDirection(layout, parent, -1, 1); if (newIcon != null) { newIcon.requestFocus(); + v.playSoundEffect(SoundEffectConstants.NAVIGATION_UP); } } wasHandled = true; @@ -887,6 +869,7 @@ public class FocusHelper { parent.getChildCount(), -1); if (newIcon != null) { newIcon.requestFocus(); + v.playSoundEffect(SoundEffectConstants.NAVIGATION_DOWN); } } wasHandled = true; diff --git a/src/com/android/launcher3/FocusIndicatorView.java b/src/com/android/launcher3/FocusIndicatorView.java new file mode 100644 index 000000000..12b7a4076 --- /dev/null +++ b/src/com/android/launcher3/FocusIndicatorView.java @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2011 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.graphics.Canvas; +import android.util.AttributeSet; +import android.util.Pair; +import android.view.View; +import android.view.ViewParent; + +public class FocusIndicatorView extends View implements View.OnFocusChangeListener { + + // It can be any number >0. The view is resized using scaleX and scaleY. + static final int DEFAULT_LAYOUT_SIZE = 100; + private static final float MIN_VISIBLE_ALPHA = 0.2f; + + private static final int[] sTempPos = new int[2]; + private static final int[] sTempShift = new int[2]; + + private final int[] mIndicatorPos = new int[2]; + private final int[] mTargetViewPos = new int[2]; + + private View mLastFocusedView; + private boolean mInitiated; + + private Pair<View, Boolean> mPendingCall; + + public FocusIndicatorView(Context context) { + this(context, null); + } + + public FocusIndicatorView(Context context, AttributeSet attrs) { + super(context, attrs); + setAlpha(0); + setBackgroundColor(getResources().getColor(R.color.focused_background)); + } + + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + super.onSizeChanged(w, h, oldw, oldh); + + // Redraw if it is already showing. This avoids a bug where the height changes by a small + // amount on connecting/disconnecting a bluetooth keyboard. + if (mLastFocusedView != null) { + mPendingCall = Pair.create(mLastFocusedView, Boolean.TRUE); + invalidate(); + } + } + + @Override + public void onFocusChange(View v, boolean hasFocus) { + mPendingCall = null; + if (!mInitiated && (getWidth() == 0)) { + // View not yet laid out. Wait until the view is ready to be drawn, so that be can + // get the location on screen. + mPendingCall = Pair.create(v, hasFocus); + invalidate(); + return; + } + + if (!mInitiated) { + getLocationRelativeToParentPagedView(this, mIndicatorPos); + mInitiated = true; + } + + if (hasFocus) { + int indicatorWidth = getWidth(); + int indicatorHeight = getHeight(); + + float scaleX = v.getScaleX() * v.getWidth() / indicatorWidth; + float scaleY = v.getScaleY() * v.getHeight() / indicatorHeight; + + getLocationRelativeToParentPagedView(v, mTargetViewPos); + float x = mTargetViewPos[0] - mIndicatorPos[0] - (1 - scaleX) * indicatorWidth / 2; + float y = mTargetViewPos[1] - mIndicatorPos[1] - (1 - scaleY) * indicatorHeight / 2; + + if (getAlpha() > MIN_VISIBLE_ALPHA) { + animate() + .translationX(x) + .translationY(y) + .scaleX(scaleX) + .scaleY(scaleY) + .alpha(1); + } else { + setTranslationX(x); + setTranslationY(y); + setScaleX(scaleX); + setScaleY(scaleY); + animate().alpha(1); + } + mLastFocusedView = v; + } else { + if (mLastFocusedView == v) { + mLastFocusedView = null; + animate().alpha(0); + } + } + } + + @Override + protected void onDraw(Canvas canvas) { + if (mPendingCall != null) { + onFocusChange(mPendingCall.first, mPendingCall.second); + } + } + + /** + * Gets the location of a view relative in the window, off-setting any shift due to + * page view scroll + */ + private static void getLocationRelativeToParentPagedView(View v, int[] pos) { + getPagedViewScrollShift(v, sTempShift); + v.getLocationInWindow(sTempPos); + pos[0] = sTempPos[0] + sTempShift[0]; + pos[1] = sTempPos[1] + sTempShift[1]; + } + + private static void getPagedViewScrollShift(View child, int[] shift) { + ViewParent parent = child.getParent(); + if (parent instanceof PagedView) { + View parentView = (View) parent; + child.getLocationInWindow(sTempPos); + shift[0] = parentView.getPaddingLeft() - sTempPos[0]; + shift[1] = -(int) child.getTranslationY(); + } else if (parent instanceof View) { + getPagedViewScrollShift((View) parent, shift); + } else { + shift[0] = shift[1] = 0; + } + } +} diff --git a/src/com/android/launcher3/Folder.java b/src/com/android/launcher3/Folder.java index b4c399266..1890af47d 100644 --- a/src/com/android/launcher3/Folder.java +++ b/src/com/android/launcher3/Folder.java @@ -18,6 +18,7 @@ package com.android.launcher3; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; +import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.animation.PropertyValuesHolder; import android.content.Context; @@ -40,6 +41,7 @@ import android.view.MotionEvent; import android.view.View; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityManager; +import android.view.animation.AccelerateInterpolator; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputMethodManager; import android.widget.LinearLayout; @@ -72,6 +74,8 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList private static final int CLOSE_FOLDER_DELAY_MS = 150; private int mExpandDuration; + private int mMaterialExpandDuration; + private int mMaterialExpandStagger; protected CellLayout mContent; private ScrollView mScrollView; private final LayoutInflater mInflater; @@ -112,9 +116,7 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList private static String sDefaultFolderName; private static String sHintText; - private int DRAG_MODE_NONE = 0; - private int DRAG_MODE_REORDER = 1; - private int mDragMode = DRAG_MODE_NONE; + private FocusIndicatorView mFocusIndicatorHandler; // We avoid measuring the scroll view with a 0 width or height, as this // results in CellLayout being measured as UNSPECIFIED, which it does @@ -157,7 +159,9 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList mInputMethodManager = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE); - mExpandDuration = res.getInteger(R.integer.config_folderAnimDuration); + mExpandDuration = res.getInteger(R.integer.config_folderExpandDuration); + mMaterialExpandDuration = res.getInteger(R.integer.config_materialFolderExpandDuration); + mMaterialExpandStagger = res.getInteger(R.integer.config_materialFolderExpandStagger); if (sDefaultFolderName == null) { sDefaultFolderName = res.getString(R.string.folder_name); @@ -178,6 +182,11 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList mScrollView = (ScrollView) findViewById(R.id.scroll_view); mContent = (CellLayout) findViewById(R.id.folder_content); + mFocusIndicatorHandler = new FocusIndicatorView(getContext()); + mContent.addView(mFocusIndicatorHandler, 0); + mFocusIndicatorHandler.getLayoutParams().height = FocusIndicatorView.DEFAULT_LAYOUT_SIZE; + mFocusIndicatorHandler.getLayoutParams().width = FocusIndicatorView.DEFAULT_LAYOUT_SIZE; + LauncherAppState app = LauncherAppState.getInstance(); DeviceProfile grid = app.getDynamicGrid().getDeviceProfile(); @@ -239,9 +248,6 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList return false; } - mLauncher.getLauncherClings().dismissFolderCling(null); - - mLauncher.getWorkspace().onDragStartedWithItem(v); mLauncher.getWorkspace().beginDragShared(v, this); mCurrentDragInfo = item; @@ -303,6 +309,10 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList return mFolderName; } + public CellLayout getContent() { + return mContent; + } + /** * We need to handle touch events to prevent them from falling through to the workspace below. */ @@ -387,7 +397,7 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList // We rearrange the items in case there are any empty gaps setupContentForNumItems(count); - // If our folder has too many items we prune them from the list. This is an issue + // If our folder has too many items we prune them from the list. This is an issue // when upgrading from the old Folders implementation which could contain an unlimited // number of items. for (ShortcutInfo item: overflow) { @@ -439,18 +449,93 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList mState = STATE_SMALL; } - public void animateOpen() { - positionAndSizeAsIcon(); + private void prepareReveal() { + setScaleX(1f); + setScaleY(1f); + setAlpha(1f); + mState = STATE_SMALL; + } + public void animateOpen() { if (!(getParent() instanceof DragLayer)) return; - centerAboutIcon(); - PropertyValuesHolder alpha = PropertyValuesHolder.ofFloat("alpha", 1); - PropertyValuesHolder scaleX = PropertyValuesHolder.ofFloat("scaleX", 1.0f); - PropertyValuesHolder scaleY = PropertyValuesHolder.ofFloat("scaleY", 1.0f); - final ObjectAnimator oa = - LauncherAnimUtils.ofPropertyValuesHolder(this, alpha, scaleX, scaleY); - oa.addListener(new AnimatorListenerAdapter() { + Animator openFolderAnim = null; + final Runnable onCompleteRunnable; + if (!Utilities.isLmpOrAbove()) { + positionAndSizeAsIcon(); + centerAboutIcon(); + + PropertyValuesHolder alpha = PropertyValuesHolder.ofFloat("alpha", 1); + PropertyValuesHolder scaleX = PropertyValuesHolder.ofFloat("scaleX", 1.0f); + PropertyValuesHolder scaleY = PropertyValuesHolder.ofFloat("scaleY", 1.0f); + final ObjectAnimator oa = + LauncherAnimUtils.ofPropertyValuesHolder(this, alpha, scaleX, scaleY); + oa.setDuration(mExpandDuration); + openFolderAnim = oa; + + setLayerType(LAYER_TYPE_HARDWARE, null); + onCompleteRunnable = new Runnable() { + @Override + public void run() { + setLayerType(LAYER_TYPE_NONE, null); + } + }; + } else { + prepareReveal(); + centerAboutIcon(); + + int width = getPaddingLeft() + getPaddingRight() + mContent.getDesiredWidth(); + int height = getFolderHeight(); + + float transX = - 0.075f * (width / 2 - getPivotX()); + float transY = - 0.075f * (height / 2 - getPivotY()); + setTranslationX(transX); + setTranslationY(transY); + PropertyValuesHolder tx = PropertyValuesHolder.ofFloat("translationX", transX, 0); + PropertyValuesHolder ty = PropertyValuesHolder.ofFloat("translationY", transY, 0); + + int rx = (int) Math.max(Math.max(width - getPivotX(), 0), getPivotX()); + int ry = (int) Math.max(Math.max(height - getPivotY(), 0), getPivotY()); + float radius = (float) Math.sqrt(rx * rx + ry * ry); + AnimatorSet anim = LauncherAnimUtils.createAnimatorSet(); + Animator reveal = LauncherAnimUtils.createCircularReveal(this, (int) getPivotX(), + (int) getPivotY(), 0, radius); + reveal.setDuration(mMaterialExpandDuration); + reveal.setInterpolator(new LogDecelerateInterpolator(100, 0)); + + mContent.setAlpha(0f); + Animator iconsAlpha = LauncherAnimUtils.ofFloat(mContent, "alpha", 0f, 1f); + iconsAlpha.setDuration(mMaterialExpandDuration); + iconsAlpha.setStartDelay(mMaterialExpandStagger); + iconsAlpha.setInterpolator(new AccelerateInterpolator(1.5f)); + + mFolderName.setAlpha(0f); + Animator textAlpha = LauncherAnimUtils.ofFloat(mFolderName, "alpha", 0f, 1f); + textAlpha.setDuration(mMaterialExpandDuration); + textAlpha.setStartDelay(mMaterialExpandStagger); + textAlpha.setInterpolator(new AccelerateInterpolator(1.5f)); + + Animator drift = LauncherAnimUtils.ofPropertyValuesHolder(this, tx, ty); + drift.setDuration(mMaterialExpandDuration); + drift.setStartDelay(mMaterialExpandStagger); + drift.setInterpolator(new LogDecelerateInterpolator(60, 0)); + + anim.play(drift); + anim.play(iconsAlpha); + anim.play(textAlpha); + anim.play(reveal); + + openFolderAnim = anim; + + mContent.setLayerType(LAYER_TYPE_HARDWARE, null); + onCompleteRunnable = new Runnable() { + @Override + public void run() { + mContent.setLayerType(LAYER_TYPE_NONE, null); + } + }; + } + openFolderAnim.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationStart(Animator animation) { sendCustomAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED, @@ -461,23 +546,15 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList @Override public void onAnimationEnd(Animator animation) { mState = STATE_OPEN; - setLayerType(LAYER_TYPE_NONE, null); - // Only show cling if we are not in the middle of a drag - this would be quite jarring. - if (!mDragController.isDragging()) { - Cling cling = mLauncher.getLauncherClings().showFoldersCling(); - if (cling != null) { - cling.bringScrimToFront(); - bringToFront(); - cling.bringToFront(); - } + if (onCompleteRunnable != null) { + onCompleteRunnable.run(); } + setFocusOnFirstChild(); } }); - oa.setDuration(mExpandDuration); - setLayerType(LAYER_TYPE_HARDWARE, null); - oa.start(); + openFolderAnim.start(); // Make sure the folder picks up the last drag move even if the finger doesn't move. if (mDragController.isDragging()) { @@ -563,23 +640,18 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList protected View createAndAddShortcut(ShortcutInfo item) { final BubbleTextView textView = - (BubbleTextView) mInflater.inflate(R.layout.application, this, false); - textView.setCompoundDrawables(null, - Utilities.createIconDrawable(item.getIcon(mIconCache)), null, null); - textView.setText(item.title); - textView.setTag(item); - textView.setTextColor(getResources().getColor(R.color.folder_items_text_color)); - textView.setShadowsEnabled(false); - textView.setGlowColor(getResources().getColor(R.color.folder_items_glow_color)); + (BubbleTextView) mInflater.inflate(R.layout.folder_application, this, false); + textView.applyFromShortcutInfo(item, mIconCache, false); textView.setOnClickListener(this); textView.setOnLongClickListener(this); + textView.setOnFocusChangeListener(mFocusIndicatorHandler); // We need to check here to verify that the given item's location isn't already occupied // by another item. if (mContent.getChildAt(item.cellX, item.cellY) != null || item.cellX < 0 || item.cellY < 0 || item.cellX >= mContent.getCountX() || item.cellY >= mContent.getCountY()) { - // This shouldn't happen, log it. + // This shouldn't happen, log it. Log.e(TAG, "Folder order not properly persisted during bind"); if (!findAndSetEmptyCells(item)) { return null; @@ -695,9 +767,6 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList mReorderAlarm.setAlarm(REORDER_DELAY); mPreviousTargetCell[0] = mTargetCell[0]; mPreviousTargetCell[1] = mTargetCell[1]; - mDragMode = DRAG_MODE_REORDER; - } else { - mDragMode = DRAG_MODE_NONE; } } } @@ -753,7 +822,6 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList mOnExitAlarm.setAlarm(ON_EXIT_CLOSE_DELAY); } mReorderAlarm.cancelAlarm(); - mDragMode = DRAG_MODE_NONE; } public void onDropCompleted(final View target, final DragObject d, @@ -793,12 +861,6 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList } } - // This is kind of hacky, but in general, dropping on the workspace handles removing - // the extra screen, but dropping elsewhere (back to self, or onto delete) doesn't. - if (target != mLauncher.getWorkspace()) { - mLauncher.getWorkspace().removeExtraEmptyScreen(true, null); - } - mDeleteFolderOnDropCompleted = false; mDragInProgress = false; mItemAddedBackToSelfViaIcon = false; @@ -1172,21 +1234,15 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList public void onDrop(DragObject d) { Runnable cleanUpRunnable = null; - // If we are coming from All Apps space, we need to remove the extra empty screen (which is - // normally done in Workspace#onDropExternal, as well zoom back in and close the folder. + // If we are coming from All Apps space, we defer removing the extra empty screen + // until the folder closes if (d.dragSource != mLauncher.getWorkspace() && !(d.dragSource instanceof Folder)) { cleanUpRunnable = new Runnable() { @Override public void run() { - mLauncher.getWorkspace().removeExtraEmptyScreen(false, new Runnable() { - @Override - public void run() { - mLauncher.closeFolder(); - mLauncher.exitSpringLoadedDragModeDelayed(true, - Launcher.EXIT_SPRINGLOADED_MODE_SHORT_TIMEOUT_FOLDER_CLOSE, - null); - } - }, CLOSE_FOLDER_DELAY_MS, false); + mLauncher.exitSpringLoadedDragModeDelayed(true, + Launcher.EXIT_SPRINGLOADED_MODE_SHORT_TIMEOUT, + null); } }; } @@ -1196,6 +1252,18 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList if (mIsExternalDrag) { si.cellX = mEmptyCell[0]; si.cellY = mEmptyCell[1]; + + // Actually move the item in the database if it was an external drag. Call this + // before creating the view, so that ShortcutInfo is updated appropriately. + LauncherModel.addOrMoveItemInDatabase( + mLauncher, si, mInfo.id, 0, si.cellX, si.cellY); + + // We only need to update the locations if it doesn't get handled in #onDropCompleted. + if (d.dragSource != this) { + updateItemLocationsInDatabaseBatch(); + } + mIsExternalDrag = false; + currentDragView = createAndAddShortcut(si); } else { currentDragView = mCurrentDragView; @@ -1223,22 +1291,12 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList mItemsInvalidated = true; setupContentDimensions(getItemCount()); - // Actually move the item in the database if it was an external drag. - if (mIsExternalDrag) { - LauncherModel.addOrMoveItemInDatabase( - mLauncher, si, mInfo.id, 0, si.cellX, si.cellY); - - // We only need to update the locations if it doesn't get handled in #onDropCompleted. - if (d.dragSource != this) { - updateItemLocationsInDatabaseBatch(); - } - mIsExternalDrag = false; - } - // Temporarily suppress the listener, as we did all the work already here. mSuppressOnAdd = true; mInfo.add(si); mSuppressOnAdd = false; + // Clear the drag info, as it is no longer being dragged. + mCurrentDragInfo = null; } // This is used so the item doesn't immediately appear in the folder when added. In one case diff --git a/src/com/android/launcher3/FolderIcon.java b/src/com/android/launcher3/FolderIcon.java index 78026f162..a359f1180 100644 --- a/src/com/android/launcher3/FolderIcon.java +++ b/src/com/android/launcher3/FolderIcon.java @@ -33,6 +33,7 @@ import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; +import android.view.ViewConfiguration; import android.view.ViewGroup; import android.view.animation.AccelerateInterpolator; import android.view.animation.DecelerateInterpolator; @@ -70,7 +71,7 @@ public class FolderIcon extends FrameLayout implements FolderListener { private static final float OUTER_RING_GROWTH_FACTOR = 0.3f; // The amount of vertical spread between items in the stack [0...1] - private static final float PERSPECTIVE_SHIFT_FACTOR = 0.24f; + private static final float PERSPECTIVE_SHIFT_FACTOR = 0.18f; // Flag as to whether or not to draw an outer ring. Currently none is designed. public static final boolean HAS_OUTER_RING = true; @@ -105,6 +106,8 @@ public class FolderIcon extends FrameLayout implements FolderListener { boolean mAnimating = false; private Rect mOldBounds = new Rect(); + private float mSlop; + private PreviewItemDrawingParams mParams = new PreviewItemDrawingParams(0, 0, 0, 0); private PreviewItemDrawingParams mAnimParams = new PreviewItemDrawingParams(0, 0, 0, 0); private ArrayList<ShortcutInfo> mHiddenItems = new ArrayList<ShortcutInfo>(); @@ -130,7 +133,7 @@ public class FolderIcon extends FrameLayout implements FolderListener { final ViewGroup cellLayoutChildren = (ViewGroup) getParent(); final ViewGroup cellLayout = (ViewGroup) cellLayoutChildren.getParent(); final Workspace workspace = (Workspace) cellLayout.getParent(); - return !workspace.isSmall(); + return !workspace.workspaceInModalState(); } static FolderIcon fromXml(int resId, Launcher launcher, ViewGroup group, @@ -175,6 +178,7 @@ public class FolderIcon extends FrameLayout implements FolderListener { icon.mFolderRingAnimator = new FolderRingAnimator(launcher, icon); folderInfo.addListener(icon); + icon.setOnFocusChangeListener(launcher.mFocusHandler); return icon; } @@ -308,7 +312,7 @@ public class FolderIcon extends FrameLayout implements FolderListener { } } - Folder getFolder() { + public Folder getFolder() { return mFolder; } @@ -341,7 +345,12 @@ public class FolderIcon extends FrameLayout implements FolderListener { mFolderRingAnimator.animateToAcceptState(); layout.showFolderAccept(mFolderRingAnimator); mOpenAlarm.setOnAlarmListener(mOnOpenListener); - if (SPRING_LOADING_ENABLED) { + if (SPRING_LOADING_ENABLED && + ((dragInfo instanceof AppInfo) || (dragInfo instanceof ShortcutInfo))) { + // TODO: we currently don't support spring-loading for PendingAddShortcutInfos even + // though widget-style shortcuts can be added to folders. The issue is that we need + // to deal with configuration activities which are currently handled in + // Workspace#onDropExternal. mOpenAlarm.setAlarm(ON_OPEN_DELAY); } mDragInfo = (ItemInfo) dragInfo; @@ -359,6 +368,7 @@ public class FolderIcon extends FrameLayout implements FolderListener { item.spanX = 1; item.spanY = 1; } else { + // ShortcutInfo item = (ShortcutInfo) mDragInfo; } mFolder.beginExternalDrag(item); @@ -371,7 +381,7 @@ public class FolderIcon extends FrameLayout implements FolderListener { float scaleRelativeToDragLayer, Runnable postAnimationRunnable) { // These correspond two the drawable and view that the icon was dropped _onto_ - Drawable animateDrawable = ((TextView) destView).getCompoundDrawables()[1]; + Drawable animateDrawable = getTopDrawable((TextView) destView); computePreviewDrawingParams(animateDrawable.getIntrinsicWidth(), destView.getMeasuredWidth()); @@ -385,8 +395,8 @@ public class FolderIcon extends FrameLayout implements FolderListener { } public void performDestroyAnimation(final View finalView, Runnable onCompleteRunnable) { - Drawable animateDrawable = ((TextView) finalView).getCompoundDrawables()[1]; - computePreviewDrawingParams(animateDrawable.getIntrinsicWidth(), + Drawable animateDrawable = getTopDrawable((TextView) finalView); + computePreviewDrawingParams(animateDrawable.getIntrinsicWidth(), finalView.getMeasuredWidth()); // This will animate the first item from it's position as an icon into its @@ -492,6 +502,7 @@ public class FolderIcon extends FrameLayout implements FolderListener { int adjustedAvailableSpace = (int) ((mAvailableSpaceInPreview / 2) * (1 + 0.8f)); int unscaledHeight = (int) (mIntrinsicIconSize * (1 + PERSPECTIVE_SHIFT_FACTOR)); + mBaselineIconScale = (1.0f * adjustedAvailableSpace / unscaledHeight); mBaselineIconSize = (int) (mIntrinsicIconSize * mBaselineIconScale); @@ -546,7 +557,7 @@ public class FolderIcon extends FrameLayout implements FolderListener { // We want to imagine our coordinates from the bottom left, growing up and to the // right. This is natural for the x-axis, but for the y-axis, we have to invert things. float transY = mAvailableSpaceInPreview - (offset + scaledSize + scaleOffsetCorrection) + getPaddingTop(); - float transX = offset + scaleOffsetCorrection; + float transX = (mAvailableSpaceInPreview - scaledSize) / 2; float totalScale = mBaselineIconScale * scale; final int overlayAlpha = (int) (80 * (1 - r)); @@ -570,10 +581,18 @@ public class FolderIcon extends FrameLayout implements FolderListener { if (d != null) { mOldBounds.set(d.getBounds()); d.setBounds(0, 0, mIntrinsicIconSize, mIntrinsicIconSize); - d.setColorFilter(Color.argb(params.overlayAlpha, 255, 255, 255), - PorterDuff.Mode.SRC_ATOP); - d.draw(canvas); - d.clearColorFilter(); + if (d instanceof FastBitmapDrawable) { + FastBitmapDrawable fd = (FastBitmapDrawable) d; + int oldBrightness = fd.getBrightness(); + fd.setBrightness(params.overlayAlpha); + d.draw(canvas); + fd.setBrightness(oldBrightness); + } else { + d.setColorFilter(Color.argb(params.overlayAlpha, 255, 255, 255), + PorterDuff.Mode.SRC_ATOP); + d.draw(canvas); + d.clearColorFilter(); + } d.setBounds(mOldBounds); } canvas.restore(); @@ -595,7 +614,7 @@ public class FolderIcon extends FrameLayout implements FolderListener { computePreviewDrawingParams(mAnimParams.drawable); } else { v = (TextView) items.get(0); - d = v.getCompoundDrawables()[1]; + d = getTopDrawable(v); computePreviewDrawingParams(d); } @@ -604,7 +623,7 @@ public class FolderIcon extends FrameLayout implements FolderListener { for (int i = nItemsInPreview - 1; i >= 0; i--) { v = (TextView) items.get(i); if (!mHiddenItems.contains(v.getTag())) { - d = v.getCompoundDrawables()[1]; + d = getTopDrawable(v); mParams = computePreviewItemDrawingParams(i, mParams); mParams.drawable = d; drawPreviewItem(canvas, mParams); @@ -615,6 +634,11 @@ public class FolderIcon extends FrameLayout implements FolderListener { } } + private Drawable getTopDrawable(TextView v) { + Drawable d = v.getCompoundDrawables()[1]; + return (d instanceof PreloadIconDrawable) ? ((PreloadIconDrawable) d).mIcon : d; + } + private void animateFirstItem(final Drawable d, int duration, final boolean reverse, final Runnable onCompleteRunnable) { final PreviewItemDrawingParams finalParams = computePreviewItemDrawingParams(0, null); @@ -703,11 +727,22 @@ public class FolderIcon extends FrameLayout implements FolderListener { case MotionEvent.ACTION_UP: mLongPressHelper.cancelLongPress(); break; + case MotionEvent.ACTION_MOVE: + if (!Utilities.pointInView(this, event.getX(), event.getY(), mSlop)) { + mLongPressHelper.cancelLongPress(); + } + break; } return result; } @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + mSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop(); + } + + @Override public void cancelLongPress() { super.cancelLongPress(); diff --git a/src/com/android/launcher3/FolderInfo.java b/src/com/android/launcher3/FolderInfo.java index d45e4e47b..85a792f4b 100644 --- a/src/com/android/launcher3/FolderInfo.java +++ b/src/com/android/launcher3/FolderInfo.java @@ -17,13 +17,17 @@ package com.android.launcher3; import android.content.ContentValues; +import android.content.Context; + +import com.android.launcher3.compat.UserHandleCompat; import java.util.ArrayList; +import java.util.Arrays; /** * Represents a folder containing shortcuts or apps. */ -class FolderInfo extends ItemInfo { +public class FolderInfo extends ItemInfo { /** * Whether this folder has been opened @@ -39,6 +43,7 @@ class FolderInfo extends ItemInfo { FolderInfo() { itemType = LauncherSettings.Favorites.ITEM_TYPE_FOLDER; + user = UserHandleCompat.myUserHandle(); } /** @@ -75,8 +80,8 @@ class FolderInfo extends ItemInfo { } @Override - void onAddToDatabase(ContentValues values) { - super.onAddToDatabase(values); + void onAddToDatabase(Context context, ContentValues values) { + super.onAddToDatabase(context, values); values.put(LauncherSettings.Favorites.TITLE, title.toString()); } @@ -114,6 +119,6 @@ class FolderInfo extends ItemInfo { return "FolderInfo(id=" + this.id + " type=" + this.itemType + " container=" + this.container + " screen=" + screenId + " cellX=" + cellX + " cellY=" + cellY + " spanX=" + spanX - + " spanY=" + spanY + " dropPos=" + dropPos + ")"; + + " spanY=" + spanY + " dropPos=" + Arrays.toString(dropPos) + ")"; } } diff --git a/src/com/android/launcher3/HideFromAccessibilityHelper.java b/src/com/android/launcher3/HideFromAccessibilityHelper.java deleted file mode 100644 index 75cbb1b1e..000000000 --- a/src/com/android/launcher3/HideFromAccessibilityHelper.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright (C) 2012 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.view.View; -import android.view.ViewGroup; -import android.view.ViewGroup.OnHierarchyChangeListener; - -import java.util.HashMap; - -public class HideFromAccessibilityHelper implements OnHierarchyChangeListener { - private HashMap<View, Integer> mPreviousValues; - boolean mHide; - boolean mOnlyAllApps; - - public HideFromAccessibilityHelper() { - mPreviousValues = new HashMap<View, Integer>(); - mHide = false; - } - - public void setImportantForAccessibilityToNo(View v, boolean onlyAllApps) { - mOnlyAllApps = onlyAllApps; - setImportantForAccessibilityToNoHelper(v); - mHide = true; - } - - private void setImportantForAccessibilityToNoHelper(View v) { - mPreviousValues.put(v, v.getImportantForAccessibility()); - v.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO); - - // Call method on children recursively - if (v instanceof ViewGroup) { - ViewGroup vg = (ViewGroup) v; - vg.setOnHierarchyChangeListener(this); - for (int i = 0; i < vg.getChildCount(); i++) { - View child = vg.getChildAt(i); - - if (includeView(child)) { - setImportantForAccessibilityToNoHelper(child); - } - } - } - } - - public void restoreImportantForAccessibility(View v) { - if (mHide) { - restoreImportantForAccessibilityHelper(v); - } - mHide = false; - } - - private void restoreImportantForAccessibilityHelper(View v) { - Integer important = mPreviousValues.get(v); - v.setImportantForAccessibility(important); - mPreviousValues.remove(v); - - // Call method on children recursively - if (v instanceof ViewGroup) { - ViewGroup vg = (ViewGroup) v; - - // We assume if a class implements OnHierarchyChangeListener, it listens - // to changes to any of its children (happens to be the case in Launcher) - if (vg instanceof OnHierarchyChangeListener) { - vg.setOnHierarchyChangeListener((OnHierarchyChangeListener) vg); - } else { - vg.setOnHierarchyChangeListener(null); - } - for (int i = 0; i < vg.getChildCount(); i++) { - View child = vg.getChildAt(i); - if (includeView(child)) { - restoreImportantForAccessibilityHelper(child); - } - } - } - } - - public void onChildViewAdded(View parent, View child) { - if (mHide && includeView(child)) { - setImportantForAccessibilityToNoHelper(child); - } - } - - public void onChildViewRemoved(View parent, View child) { - if (mHide && includeView(child)) { - restoreImportantForAccessibilityHelper(child); - } - } - - private boolean includeView(View v) { - return !hasAncestorOfType(v, Cling.class) && - (!mOnlyAllApps || hasAncestorOfType(v, AppsCustomizeTabHost.class)); - } - - private boolean hasAncestorOfType(View v, Class c) { - return v != null && - (v.getClass().equals(c) || - (v.getParent() instanceof ViewGroup && - hasAncestorOfType((ViewGroup) v.getParent(), c))); - } -}
\ No newline at end of file diff --git a/src/com/android/launcher3/HolographicOutlineHelper.java b/src/com/android/launcher3/HolographicOutlineHelper.java index d7b960aba..b1e0e68a4 100644 --- a/src/com/android/launcher3/HolographicOutlineHelper.java +++ b/src/com/android/launcher3/HolographicOutlineHelper.java @@ -20,48 +20,49 @@ import android.content.Context; import android.graphics.Bitmap; import android.graphics.BlurMaskFilter; import android.graphics.Canvas; +import android.graphics.Color; import android.graphics.Paint; import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; +import android.graphics.Rect; +import android.graphics.Region.Op; public class HolographicOutlineHelper { - private final Paint mHolographicPaint = new Paint(); + + private static final Rect sTempRect = new Rect(); + + private final Canvas mCanvas = new Canvas(); + private final Paint mDrawPaint = new Paint(); private final Paint mBlurPaint = new Paint(); private final Paint mErasePaint = new Paint(); - public int mMaxOuterBlurRadius; - public int mMinOuterBlurRadius; + private final BlurMaskFilter mMediumOuterBlurMaskFilter; + private final BlurMaskFilter mThinOuterBlurMaskFilter; + private final BlurMaskFilter mMediumInnerBlurMaskFilter; - private BlurMaskFilter mExtraThickOuterBlurMaskFilter; - private BlurMaskFilter mThickOuterBlurMaskFilter; - private BlurMaskFilter mMediumOuterBlurMaskFilter; - private BlurMaskFilter mThinOuterBlurMaskFilter; - private BlurMaskFilter mThickInnerBlurMaskFilter; - private BlurMaskFilter mExtraThickInnerBlurMaskFilter; - private BlurMaskFilter mMediumInnerBlurMaskFilter; + private final BlurMaskFilter mShaowBlurMaskFilter; + private final int mShadowOffset; - private static final int THICK = 0; - private static final int MEDIUM = 1; - private static final int EXTRA_THICK = 2; + /** + * Padding used when creating shadow bitmap; + */ + final int shadowBitmapPadding; static HolographicOutlineHelper INSTANCE; private HolographicOutlineHelper(Context context) { final float scale = LauncherAppState.getInstance().getScreenDensity(); - mMinOuterBlurRadius = (int) (scale * 1.0f); - mMaxOuterBlurRadius = (int) (scale * 12.0f); - - mExtraThickOuterBlurMaskFilter = new BlurMaskFilter(scale * 12.0f, BlurMaskFilter.Blur.OUTER); - mThickOuterBlurMaskFilter = new BlurMaskFilter(scale * 6.0f, BlurMaskFilter.Blur.OUTER); mMediumOuterBlurMaskFilter = new BlurMaskFilter(scale * 2.0f, BlurMaskFilter.Blur.OUTER); mThinOuterBlurMaskFilter = new BlurMaskFilter(scale * 1.0f, BlurMaskFilter.Blur.OUTER); - mExtraThickInnerBlurMaskFilter = new BlurMaskFilter(scale * 6.0f, BlurMaskFilter.Blur.NORMAL); - mThickInnerBlurMaskFilter = new BlurMaskFilter(scale * 4.0f, BlurMaskFilter.Blur.NORMAL); mMediumInnerBlurMaskFilter = new BlurMaskFilter(scale * 2.0f, BlurMaskFilter.Blur.NORMAL); - mHolographicPaint.setFilterBitmap(true); - mHolographicPaint.setAntiAlias(true); + mShaowBlurMaskFilter = new BlurMaskFilter(scale * 4.0f, BlurMaskFilter.Blur.NORMAL); + mShadowOffset = (int) (scale * 2.0f); + shadowBitmapPadding = (int) (scale * 4.0f); + + mDrawPaint.setFilterBitmap(true); + mDrawPaint.setAntiAlias(true); mBlurPaint.setFilterBitmap(true); mBlurPaint.setAntiAlias(true); mErasePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); @@ -77,37 +78,15 @@ public class HolographicOutlineHelper { } /** - * Returns the interpolated holographic highlight alpha for the effect we want when scrolling - * pages. - */ - public static float highlightAlphaInterpolator(float r) { - float maxAlpha = 0.6f; - return (float) Math.pow(maxAlpha * (1.0f - r), 1.5f); - } - - /** - * Returns the interpolated view alpha for the effect we want when scrolling pages. - */ - public static float viewAlphaInterpolator(float r) { - final float pivot = 0.95f; - if (r < pivot) { - return (float) Math.pow(r / pivot, 1.5f); - } else { - return 1.0f; - } - } - - /** * Applies a more expensive and accurate outline to whatever is currently drawn in a specified * bitmap. */ void applyExpensiveOutlineWithBlur(Bitmap srcDst, Canvas srcDstCanvas, int color, - int outlineColor, int thickness) { - applyExpensiveOutlineWithBlur(srcDst, srcDstCanvas, color, outlineColor, true, - thickness); + int outlineColor) { + applyExpensiveOutlineWithBlur(srcDst, srcDstCanvas, color, outlineColor, true); } void applyExpensiveOutlineWithBlur(Bitmap srcDst, Canvas srcDstCanvas, int color, - int outlineColor, boolean clipAlpha, int thickness) { + int outlineColor, boolean clipAlpha) { // We start by removing most of the alpha channel so as to ignore shadows, and // other types of partial transparency when defining the shape of the object @@ -127,50 +106,18 @@ public class HolographicOutlineHelper { Bitmap glowShape = srcDst.extractAlpha(); // calculate the outer blur first - BlurMaskFilter outerBlurMaskFilter; - switch (thickness) { - case EXTRA_THICK: - outerBlurMaskFilter = mExtraThickOuterBlurMaskFilter; - break; - case THICK: - outerBlurMaskFilter = mThickOuterBlurMaskFilter; - break; - case MEDIUM: - outerBlurMaskFilter = mMediumOuterBlurMaskFilter; - break; - default: - throw new RuntimeException("Invalid blur thickness"); - } - mBlurPaint.setMaskFilter(outerBlurMaskFilter); + mBlurPaint.setMaskFilter(mMediumOuterBlurMaskFilter); int[] outerBlurOffset = new int[2]; Bitmap thickOuterBlur = glowShape.extractAlpha(mBlurPaint, outerBlurOffset); - if (thickness == EXTRA_THICK) { - mBlurPaint.setMaskFilter(mMediumOuterBlurMaskFilter); - } else { - mBlurPaint.setMaskFilter(mThinOuterBlurMaskFilter); - } + mBlurPaint.setMaskFilter(mThinOuterBlurMaskFilter); int[] brightOutlineOffset = new int[2]; Bitmap brightOutline = glowShape.extractAlpha(mBlurPaint, brightOutlineOffset); // calculate the inner blur srcDstCanvas.setBitmap(glowShape); srcDstCanvas.drawColor(0xFF000000, PorterDuff.Mode.SRC_OUT); - BlurMaskFilter innerBlurMaskFilter; - switch (thickness) { - case EXTRA_THICK: - innerBlurMaskFilter = mExtraThickInnerBlurMaskFilter; - break; - case THICK: - innerBlurMaskFilter = mThickInnerBlurMaskFilter; - break; - case MEDIUM: - innerBlurMaskFilter = mMediumInnerBlurMaskFilter; - break; - default: - throw new RuntimeException("Invalid blur thickness"); - } - mBlurPaint.setMaskFilter(innerBlurMaskFilter); + mBlurPaint.setMaskFilter(mMediumInnerBlurMaskFilter); int[] thickInnerBlurOffset = new int[2]; Bitmap thickInnerBlur = glowShape.extractAlpha(mBlurPaint, thickInnerBlurOffset); @@ -186,16 +133,16 @@ public class HolographicOutlineHelper { // draw the inner and outer blur srcDstCanvas.setBitmap(srcDst); srcDstCanvas.drawColor(0, PorterDuff.Mode.CLEAR); - mHolographicPaint.setColor(color); + mDrawPaint.setColor(color); srcDstCanvas.drawBitmap(thickInnerBlur, thickInnerBlurOffset[0], thickInnerBlurOffset[1], - mHolographicPaint); + mDrawPaint); srcDstCanvas.drawBitmap(thickOuterBlur, outerBlurOffset[0], outerBlurOffset[1], - mHolographicPaint); + mDrawPaint); // draw the bright outline - mHolographicPaint.setColor(outlineColor); + mDrawPaint.setColor(outlineColor); srcDstCanvas.drawBitmap(brightOutline, brightOutlineOffset[0], brightOutlineOffset[1], - mHolographicPaint); + mDrawPaint); // cleanup srcDstCanvas.setBitmap(null); @@ -205,25 +152,52 @@ public class HolographicOutlineHelper { glowShape.recycle(); } - void applyExtraThickExpensiveOutlineWithBlur(Bitmap srcDst, Canvas srcDstCanvas, int color, - int outlineColor) { - applyExpensiveOutlineWithBlur(srcDst, srcDstCanvas, color, outlineColor, EXTRA_THICK); - } - - void applyThickExpensiveOutlineWithBlur(Bitmap srcDst, Canvas srcDstCanvas, int color, - int outlineColor) { - applyExpensiveOutlineWithBlur(srcDst, srcDstCanvas, color, outlineColor, THICK); + Bitmap createMediumDropShadow(BubbleTextView view) { + final Bitmap result = Bitmap.createBitmap( + view.getWidth() + shadowBitmapPadding + shadowBitmapPadding, + view.getHeight() + shadowBitmapPadding + shadowBitmapPadding + mShadowOffset, + Bitmap.Config.ARGB_8888); + + mCanvas.setBitmap(result); + + final Rect clipRect = sTempRect; + view.getDrawingRect(sTempRect); + // adjust the clip rect so that we don't include the text label + clipRect.bottom = view.getExtendedPaddingTop() - (int) BubbleTextView.PADDING_V + + view.getLayout().getLineTop(0); + + // Draw the View into the bitmap. + // The translate of scrollX and scrollY is necessary when drawing TextViews, because + // they set scrollX and scrollY to large values to achieve centered text + mCanvas.save(); + mCanvas.scale(view.getScaleX(), view.getScaleY(), + view.getWidth() / 2 + shadowBitmapPadding, + view.getHeight() / 2 + shadowBitmapPadding); + mCanvas.translate(-view.getScrollX() + shadowBitmapPadding, + -view.getScrollY() + shadowBitmapPadding); + mCanvas.clipRect(clipRect, Op.REPLACE); + view.draw(mCanvas); + mCanvas.restore(); + + int[] blurOffst = new int[2]; + mBlurPaint.setMaskFilter(mShaowBlurMaskFilter); + Bitmap blurBitmap = result.extractAlpha(mBlurPaint, blurOffst); + + mCanvas.save(); + mCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); + mCanvas.translate(blurOffst[0], blurOffst[1]); + + mDrawPaint.setColor(Color.BLACK); + mDrawPaint.setAlpha(30); + mCanvas.drawBitmap(blurBitmap, 0, 0, mDrawPaint); + + mDrawPaint.setAlpha(60); + mCanvas.drawBitmap(blurBitmap, 0, mShadowOffset, mDrawPaint); + mCanvas.restore(); + + mCanvas.setBitmap(null); + blurBitmap.recycle(); + + return result; } - - void applyMediumExpensiveOutlineWithBlur(Bitmap srcDst, Canvas srcDstCanvas, int color, - int outlineColor, boolean clipAlpha) { - applyExpensiveOutlineWithBlur(srcDst, srcDstCanvas, color, outlineColor, clipAlpha, - MEDIUM); - } - - void applyMediumExpensiveOutlineWithBlur(Bitmap srcDst, Canvas srcDstCanvas, int color, - int outlineColor) { - applyExpensiveOutlineWithBlur(srcDst, srcDstCanvas, color, outlineColor, MEDIUM); - } - } diff --git a/src/com/android/launcher3/Hotseat.java b/src/com/android/launcher3/Hotseat.java index 59d60e381..b08272f36 100644 --- a/src/com/android/launcher3/Hotseat.java +++ b/src/com/android/launcher3/Hotseat.java @@ -64,7 +64,6 @@ public class Hotseat extends FrameLayout { public void setup(Launcher launcher) { mLauncher = launcher; - setOnKeyListener(new HotseatIconKeyEventListener()); } CellLayout getLayout() { @@ -150,21 +149,18 @@ public class Hotseat extends FrameLayout { TextView allAppsButton = (TextView) inflater.inflate(R.layout.all_apps_button, mContent, false); Drawable d = context.getResources().getDrawable(R.drawable.all_apps_button_icon); + Utilities.resizeIconDrawable(d); allAppsButton.setCompoundDrawables(null, d, null, null); allAppsButton.setContentDescription(context.getString(R.string.all_apps_button_label)); + allAppsButton.setOnKeyListener(new HotseatIconKeyEventListener()); if (mLauncher != null) { allAppsButton.setOnTouchListener(mLauncher.getHapticFeedbackTouchListener()); + mLauncher.setAllAppsButton(allAppsButton); + allAppsButton.setOnClickListener(mLauncher); + allAppsButton.setOnFocusChangeListener(mLauncher.mFocusHandler); } - allAppsButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(android.view.View v) { - if (mLauncher != null) { - mLauncher.onClickAllAppsButton(v); - } - } - }); // Note: We do this to ensure that the hotseat is always laid out in the orientation of // the hotseat in order regardless of which orientation they were added @@ -172,7 +168,7 @@ public class Hotseat extends FrameLayout { int y = getCellYFromOrder(mAllAppsButtonRank); CellLayout.LayoutParams lp = new CellLayout.LayoutParams(x,y,1,1); lp.canReorder = false; - mContent.addViewToCellLayout(allAppsButton, -1, 0, lp, true); + mContent.addViewToCellLayout(allAppsButton, -1, allAppsButton.getId(), lp, true); } } @@ -180,7 +176,7 @@ public class Hotseat extends FrameLayout { public boolean onInterceptTouchEvent(MotionEvent ev) { // We don't want any clicks to go through to the hotseat unless the workspace is in // the normal state. - if (mLauncher.getWorkspace().isSmall()) { + if (mLauncher.getWorkspace().workspaceInModalState()) { return true; } return false; diff --git a/src/com/android/launcher3/IconCache.java b/src/com/android/launcher3/IconCache.java index 827718b9e..bb71d776c 100644 --- a/src/com/android/launcher3/IconCache.java +++ b/src/com/android/launcher3/IconCache.java @@ -16,23 +16,29 @@ package com.android.launcher3; -import com.android.launcher3.backup.BackupProtos; - import android.app.ActivityManager; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.pm.ActivityInfo; +import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.ResolveInfo; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; -import android.graphics.Paint; +import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; +import android.text.TextUtils; import android.util.Log; +import com.android.launcher3.compat.LauncherActivityInfoCompat; +import com.android.launcher3.compat.LauncherAppsCompat; +import com.android.launcher3.compat.UserHandleCompat; +import com.android.launcher3.compat.UserManagerCompat; + import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; @@ -48,24 +54,52 @@ import java.util.Map.Entry; * Cache of application icons. Icons can be made from any thread. */ public class IconCache { - @SuppressWarnings("unused") + private static final String TAG = "Launcher.IconCache"; private static final int INITIAL_ICON_CACHE_CAPACITY = 50; private static final String RESOURCE_FILE_PREFIX = "icon_"; - private static final boolean DEBUG = true; + // Empty class name is used for storing package default entry. + private static final String EMPTY_CLASS_NAME = "."; + + private static final boolean DEBUG = false; private static class CacheEntry { public Bitmap icon; - public String title; + public CharSequence title; + public CharSequence contentDescription; + } + + private static class CacheKey { + public ComponentName componentName; + public UserHandleCompat user; + + CacheKey(ComponentName componentName, UserHandleCompat user) { + this.componentName = componentName; + this.user = user; + } + + @Override + public int hashCode() { + return componentName.hashCode() + user.hashCode(); + } + + @Override + public boolean equals(Object o) { + CacheKey other = (CacheKey) o; + return other.componentName.equals(componentName) && other.user.equals(user); + } } - private final Bitmap mDefaultIcon; + private final HashMap<UserHandleCompat, Bitmap> mDefaultIcons = + new HashMap<UserHandleCompat, Bitmap>(); private final Context mContext; private final PackageManager mPackageManager; - private final HashMap<ComponentName, CacheEntry> mCache = - new HashMap<ComponentName, CacheEntry>(INITIAL_ICON_CACHE_CAPACITY); + private final UserManagerCompat mUserManager; + private final LauncherAppsCompat mLauncherApps; + private final HashMap<CacheKey, CacheEntry> mCache = + new HashMap<CacheKey, CacheEntry>(INITIAL_ICON_CACHE_CAPACITY); private int mIconDpi; public IconCache(Context context) { @@ -74,10 +108,13 @@ public class IconCache { mContext = context; mPackageManager = context.getPackageManager(); + mUserManager = UserManagerCompat.getInstance(mContext); + mLauncherApps = LauncherAppsCompat.getInstance(mContext); mIconDpi = activityManager.getLauncherLargeIconDensity(); // need to set mIconDpi before getting default icon - mDefaultIcon = makeDefaultIcon(); + UserHandleCompat myUser = UserHandleCompat.myUserHandle(); + mDefaultIcons.put(myUser, makeDefaultIcon(myUser)); } public Drawable getFullResDefaultActivityIcon() { @@ -111,6 +148,10 @@ public class IconCache { return getFullResDefaultActivityIcon(); } + public int getFullResIconDpi() { + return mIconDpi; + } + public Drawable getFullResIcon(ResolveInfo info) { return getFullResIcon(info.activityInfo); } @@ -134,8 +175,9 @@ public class IconCache { return getFullResDefaultActivityIcon(); } - private Bitmap makeDefaultIcon() { - Drawable d = getFullResDefaultActivityIcon(); + private Bitmap makeDefaultIcon(UserHandleCompat user) { + Drawable unbadged = getFullResDefaultActivityIcon(); + Drawable d = mUserManager.getBadgedDrawableForUser(unbadged, user); Bitmap b = Bitmap.createBitmap(Math.max(d.getIntrinsicWidth(), 1), Math.max(d.getIntrinsicHeight(), 1), Bitmap.Config.ARGB_8888); @@ -149,24 +191,25 @@ public class IconCache { /** * Remove any records for the supplied ComponentName. */ - public void remove(ComponentName componentName) { + public void remove(ComponentName componentName, UserHandleCompat user) { synchronized (mCache) { - mCache.remove(componentName); + mCache.remove(new CacheKey(componentName, user)); } } /** * Remove any records for the supplied package name. */ - public void remove(String packageName) { - HashSet<ComponentName> forDeletion = new HashSet<ComponentName>(); - for (ComponentName componentName: mCache.keySet()) { - if (componentName.getPackageName().equals(packageName)) { - forDeletion.add(componentName); + public void remove(String packageName, UserHandleCompat user) { + HashSet<CacheKey> forDeletion = new HashSet<CacheKey>(); + for (CacheKey key: mCache.keySet()) { + if (key.componentName.getPackageName().equals(packageName) + && key.user.equals(user)) { + forDeletion.add(key); } } - for (ComponentName condemned: forDeletion) { - remove(condemned); + for (CacheKey condemned: forDeletion) { + mCache.remove(condemned); } } @@ -184,10 +227,11 @@ public class IconCache { */ public void flushInvalidIcons(DeviceProfile grid) { synchronized (mCache) { - Iterator<Entry<ComponentName, CacheEntry>> it = mCache.entrySet().iterator(); + Iterator<Entry<CacheKey, CacheEntry>> it = mCache.entrySet().iterator(); while (it.hasNext()) { final CacheEntry e = it.next().getValue(); - if (e.icon.getWidth() < grid.iconSizePx || e.icon.getHeight() < grid.iconSizePx) { + if ((e.icon != null) && (e.icon.getWidth() < grid.iconSizePx + || e.icon.getHeight() < grid.iconSizePx)) { it.remove(); } } @@ -197,100 +241,193 @@ public class IconCache { /** * Fill in "application" with the icon and label for "info." */ - public void getTitleAndIcon(AppInfo application, ResolveInfo info, + public void getTitleAndIcon(AppInfo application, LauncherActivityInfoCompat info, HashMap<Object, CharSequence> labelCache) { synchronized (mCache) { - CacheEntry entry = cacheLocked(application.componentName, info, labelCache); + CacheEntry entry = cacheLocked(application.componentName, info, labelCache, + info.getUser(), false); application.title = entry.title; application.iconBitmap = entry.icon; + application.contentDescription = entry.contentDescription; } } - public Bitmap getIcon(Intent intent) { - return getIcon(intent, null); + public Bitmap getIcon(Intent intent, UserHandleCompat user) { + return getIcon(intent, null, user, true); } - public Bitmap getIcon(Intent intent, String title) { + private Bitmap getIcon(Intent intent, String title, UserHandleCompat user, boolean usePkgIcon) { synchronized (mCache) { - final ResolveInfo resolveInfo = mPackageManager.resolveActivity(intent, 0); ComponentName component = intent.getComponent(); - + // null info means not installed, but if we have a component from the intent then + // we should still look in the cache for restored app icons. if (component == null) { - return mDefaultIcon; + return getDefaultIcon(user); } - CacheEntry entry = cacheLocked(component, resolveInfo, null); + LauncherActivityInfoCompat launcherActInfo = mLauncherApps.resolveActivity(intent, user); + CacheEntry entry = cacheLocked(component, launcherActInfo, null, user, usePkgIcon); if (title != null) { entry.title = title; + entry.contentDescription = mUserManager.getBadgedLabelForUser(title, user); } return entry.icon; } } - public Bitmap getIcon(ComponentName component, ResolveInfo resolveInfo, + /** + * Fill in "shortcutInfo" with the icon and label for "info." + */ + public void getTitleAndIcon(ShortcutInfo shortcutInfo, Intent intent, UserHandleCompat user, + boolean usePkgIcon) { + synchronized (mCache) { + ComponentName component = intent.getComponent(); + // null info means not installed, but if we have a component from the intent then + // we should still look in the cache for restored app icons. + if (component == null) { + shortcutInfo.setIcon(getDefaultIcon(user)); + shortcutInfo.title = ""; + shortcutInfo.usingFallbackIcon = true; + } else { + LauncherActivityInfoCompat launcherActInfo = + mLauncherApps.resolveActivity(intent, user); + CacheEntry entry = cacheLocked(component, launcherActInfo, null, user, usePkgIcon); + + shortcutInfo.setIcon(entry.icon); + shortcutInfo.title = entry.title; + shortcutInfo.usingFallbackIcon = isDefaultIcon(entry.icon, user); + } + } + } + + + public Bitmap getDefaultIcon(UserHandleCompat user) { + if (!mDefaultIcons.containsKey(user)) { + mDefaultIcons.put(user, makeDefaultIcon(user)); + } + return mDefaultIcons.get(user); + } + + public Bitmap getIcon(ComponentName component, LauncherActivityInfoCompat info, HashMap<Object, CharSequence> labelCache) { synchronized (mCache) { - if (resolveInfo == null || component == null) { + if (info == null || component == null) { return null; } - CacheEntry entry = cacheLocked(component, resolveInfo, labelCache); + CacheEntry entry = cacheLocked(component, info, labelCache, info.getUser(), false); return entry.icon; } } - public boolean isDefaultIcon(Bitmap icon) { - return mDefaultIcon == icon; + public boolean isDefaultIcon(Bitmap icon, UserHandleCompat user) { + return mDefaultIcons.get(user) == icon; } - private CacheEntry cacheLocked(ComponentName componentName, ResolveInfo info, - HashMap<Object, CharSequence> labelCache) { - CacheEntry entry = mCache.get(componentName); + private CacheEntry cacheLocked(ComponentName componentName, LauncherActivityInfoCompat info, + HashMap<Object, CharSequence> labelCache, UserHandleCompat user, boolean usePackageIcon) { + CacheKey cacheKey = new CacheKey(componentName, user); + CacheEntry entry = mCache.get(cacheKey); if (entry == null) { entry = new CacheEntry(); - mCache.put(componentName, entry); + mCache.put(cacheKey, entry); if (info != null) { - ComponentName key = LauncherModel.getComponentNameFromResolveInfo(info); - if (labelCache != null && labelCache.containsKey(key)) { - entry.title = labelCache.get(key).toString(); + ComponentName labelKey = info.getComponentName(); + if (labelCache != null && labelCache.containsKey(labelKey)) { + entry.title = labelCache.get(labelKey).toString(); } else { - entry.title = info.loadLabel(mPackageManager).toString(); + entry.title = info.getLabel().toString(); if (labelCache != null) { - labelCache.put(key, entry.title); + labelCache.put(labelKey, entry.title); } } - if (entry.title == null) { - entry.title = info.activityInfo.name; - } + entry.contentDescription = mUserManager.getBadgedLabelForUser(entry.title, user); entry.icon = Utilities.createIconBitmap( - getFullResIcon(info), mContext); + info.getBadgedIcon(mIconDpi), mContext); } else { entry.title = ""; - Bitmap preloaded = getPreloadedIcon(componentName); + Bitmap preloaded = getPreloadedIcon(componentName, user); if (preloaded != null) { if (DEBUG) Log.d(TAG, "using preloaded icon for " + componentName.toShortString()); entry.icon = preloaded; } else { - if (DEBUG) Log.d(TAG, "using default icon for " + - componentName.toShortString()); - entry.icon = mDefaultIcon; + if (usePackageIcon) { + CacheEntry packageEntry = getEntryForPackage( + componentName.getPackageName(), user); + if (packageEntry != null) { + if (DEBUG) Log.d(TAG, "using package default icon for " + + componentName.toShortString()); + entry.icon = packageEntry.icon; + entry.title = packageEntry.title; + } + } + if (entry.icon == null) { + if (DEBUG) Log.d(TAG, "using default icon for " + + componentName.toShortString()); + entry.icon = getDefaultIcon(user); + } } } } return entry; } + /** + * Adds a default package entry in the cache. This entry is not persisted and will be removed + * when the cache is flushed. + */ + public void cachePackageInstallInfo(String packageName, UserHandleCompat user, + Bitmap icon, CharSequence title) { + remove(packageName, user); + + CacheEntry entry = getEntryForPackage(packageName, user); + if (!TextUtils.isEmpty(title)) { + entry.title = title; + } + if (icon != null) { + entry.icon = Utilities.createIconBitmap( + new BitmapDrawable(mContext.getResources(), icon), mContext); + } + } + + /** + * Gets an entry for the package, which can be used as a fallback entry for various components. + */ + private CacheEntry getEntryForPackage(String packageName, UserHandleCompat user) { + ComponentName cn = getPackageComponent(packageName); + CacheKey cacheKey = new CacheKey(cn, user); + CacheEntry entry = mCache.get(cacheKey); + if (entry == null) { + entry = new CacheEntry(); + entry.title = ""; + mCache.put(cacheKey, entry); + + try { + ApplicationInfo info = mPackageManager.getApplicationInfo(packageName, 0); + entry.title = info.loadLabel(mPackageManager); + entry.icon = Utilities.createIconBitmap(info.loadIcon(mPackageManager), mContext); + } catch (NameNotFoundException e) { + if (DEBUG) Log.d(TAG, "Application not installed " + packageName); + } + + if (entry.icon == null) { + entry.icon = getPreloadedIcon(cn, user); + } + } + return entry; + } + public HashMap<ComponentName,Bitmap> getAllIcons() { synchronized (mCache) { HashMap<ComponentName,Bitmap> set = new HashMap<ComponentName,Bitmap>(); - for (ComponentName cn : mCache.keySet()) { - final CacheEntry e = mCache.get(cn); - set.put(cn, e.icon); + for (CacheKey ck : mCache.keySet()) { + final CacheEntry e = mCache.get(ck); + set.put(ck.componentName, e.icon); } return set; } @@ -353,9 +490,14 @@ public class IconCache { * @param componentName the component that should own the icon * @returns a bitmap if one is cached, or null. */ - private Bitmap getPreloadedIcon(ComponentName componentName) { + private Bitmap getPreloadedIcon(ComponentName componentName, UserHandleCompat user) { final String key = componentName.flattenToShortString(); + // We don't keep icons for other profiles in persistent cache. + if (!user.equals(UserHandleCompat.myUserHandle())) { + return null; + } + if (DEBUG) Log.v(TAG, "looking for pre-load icon for " + key); Bitmap icon = null; FileInputStream resourceFile = null; @@ -374,7 +516,7 @@ public class IconCache { Log.w(TAG, "failed to decode pre-load icon for " + key); } } catch (FileNotFoundException e) { - if (DEBUG) Log.d(TAG, "there is no restored icon for: " + key, e); + if (DEBUG) Log.d(TAG, "there is no restored icon for: " + key); } catch (IOException e) { Log.w(TAG, "failed to read pre-load icon for: " + key, e); } finally { @@ -387,20 +529,6 @@ public class IconCache { } } - if (icon != null) { - // TODO: handle alpha mask in the view layer - Bitmap b = Bitmap.createBitmap(Math.max(icon.getWidth(), 1), - Math.max(icon.getHeight(), 1), - Bitmap.Config.ARGB_8888); - Canvas c = new Canvas(b); - Paint paint = new Paint(); - paint.setAlpha(127); - c.drawBitmap(icon, 0, 0, paint); - c.setBitmap(null); - icon.recycle(); - icon = b; - } - return icon; } @@ -410,7 +538,11 @@ public class IconCache { * @param componentName the component that should own the icon * @returns true on success */ - public boolean deletePreloadedIcon(ComponentName componentName) { + public boolean deletePreloadedIcon(ComponentName componentName, UserHandleCompat user) { + // We don't keep icons for other profiles in persistent cache. + if (!user.equals(UserHandleCompat.myUserHandle())) { + return false; + } if (componentName == null) { return false; } @@ -428,4 +560,8 @@ public class IconCache { String filename = resourceName.replace(File.separatorChar, '_'); return RESOURCE_FILE_PREFIX + filename; } + + static ComponentName getPackageComponent(String packageName) { + return new ComponentName(packageName, EMPTY_CLASS_NAME); + } } diff --git a/src/com/android/launcher3/InfoDropTarget.java b/src/com/android/launcher3/InfoDropTarget.java index 374238c49..7e55af228 100644 --- a/src/com/android/launcher3/InfoDropTarget.java +++ b/src/com/android/launcher3/InfoDropTarget.java @@ -26,6 +26,8 @@ import android.util.AttributeSet; import android.view.View; import android.view.ViewGroup; +import com.android.launcher3.compat.UserHandleCompat; + public class InfoDropTarget extends ButtonDropTarget { private ColorStateList mOriginalTextColor; @@ -49,6 +51,13 @@ public class InfoDropTarget extends ButtonDropTarget { Resources r = getResources(); mHoverColor = r.getColor(R.color.info_target_hover_tint); mDrawable = (TransitionDrawable) getCurrentDrawable(); + + if (mDrawable == null) { + // TODO: investigate why this is ever happening. Presently only on one known device. + mDrawable = (TransitionDrawable) r.getDrawable(R.drawable.info_target_selector); + setCompoundDrawablesRelativeWithIntrinsicBounds(mDrawable, null, null, null); + } + if (null != mDrawable) { mDrawable.setCrossFadeEnabled(true); } @@ -75,8 +84,15 @@ public class InfoDropTarget extends ButtonDropTarget { } else if (d.dragInfo instanceof PendingAddItemInfo) { componentName = ((PendingAddItemInfo) d.dragInfo).componentName; } + final UserHandleCompat user; + if (d.dragInfo instanceof ItemInfo) { + user = ((ItemInfo) d.dragInfo).user; + } else { + user = UserHandleCompat.myUserHandle(); + } + if (componentName != null) { - mLauncher.startApplicationDetailsActivity(componentName); + mLauncher.startApplicationDetailsActivity(componentName, user); } // There is no post-drop animation, so clean up the DragView now diff --git a/src/com/android/launcher3/InstallShortcutReceiver.java b/src/com/android/launcher3/InstallShortcutReceiver.java index 28cef1346..2edde4fae 100644 --- a/src/com/android/launcher3/InstallShortcutReceiver.java +++ b/src/com/android/launcher3/InstallShortcutReceiver.java @@ -17,6 +17,7 @@ package com.android.launcher3; import android.content.BroadcastReceiver; +import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; @@ -29,6 +30,8 @@ import android.util.Base64; import android.util.Log; import android.widget.Toast; +import com.android.launcher3.compat.UserHandleCompat; + import org.json.JSONObject; import org.json.JSONStringer; import org.json.JSONTokener; @@ -280,19 +283,27 @@ public class InstallShortcutReceiver extends BroadcastReceiver { final boolean exists = LauncherModel.shortcutExists(context, name, intent); //final boolean allowDuplicate = data.getBooleanExtra(Launcher.EXTRA_SHORTCUT_DUPLICATE, true); - // TODO-XXX: Disable duplicates for now - if (!exists /* && allowDuplicate */) { + // If the intent specifies a package, make sure the package exists + String packageName = intent.getPackage(); + if (packageName == null) { + packageName = intent.getComponent() == null ? null : + intent.getComponent().getPackageName(); + } + if (packageName != null && !packageName.isEmpty()) { + UserHandleCompat myUserHandle = UserHandleCompat.myUserHandle(); + if (!LauncherModel.isValidPackage(context, packageName, myUserHandle)) { + if (DBG) Log.d(TAG, "Ignoring shortcut for absent package:" + intent); + continue; + } + } + + if (!exists) { // Generate a shortcut info to add into the model ShortcutInfo info = getShortcutInfo(context, pendingInfo.data, pendingInfo.launchIntent); addShortcuts.add(info); } - /* - else if (exists && !allowDuplicate) { - result = INSTALL_SHORTCUT_IS_DUPLICATE; - duplicateName = name; - } - */ + } // Notify the user once if we weren't able to place any duplicates diff --git a/src/com/android/launcher3/ItemInfo.java b/src/com/android/launcher3/ItemInfo.java index 3dc92c9c2..09b77f756 100644 --- a/src/com/android/launcher3/ItemInfo.java +++ b/src/com/android/launcher3/ItemInfo.java @@ -17,24 +17,34 @@ package com.android.launcher3; import android.content.ContentValues; +import android.content.Context; import android.content.Intent; import android.graphics.Bitmap; import android.util.Log; +import com.android.launcher3.compat.UserHandleCompat; +import com.android.launcher3.compat.UserManagerCompat; + import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.util.Arrays; /** * Represents an item in the launcher. */ public class ItemInfo { + + /** + * Intent extra to store the profile. Format: UserHandle + */ + static final String EXTRA_PROFILE = "profile"; static final int NO_ID = -1; /** * The id in the settings database for this item */ - long id = NO_ID; + public long id = NO_ID; /** * One of {@link LauncherSettings.Favorites#ITEM_TYPE_APPLICATION}, @@ -42,7 +52,7 @@ public class ItemInfo { * {@link LauncherSettings.Favorites#ITEM_TYPE_FOLDER}, or * {@link LauncherSettings.Favorites#ITEM_TYPE_APPWIDGET}. */ - int itemType; + public int itemType; /** * The id of the container that holds this item. For the desktop, this will be @@ -50,27 +60,27 @@ public class ItemInfo { * will be {@link #NO_ID} (since it is not stored in the settings DB). For user folders * it will be the id of the folder. */ - long container = NO_ID; + public long container = NO_ID; /** * Iindicates the screen in which the shortcut appears. */ - long screenId = -1; + public long screenId = -1; /** * Indicates the X position of the associated cell. */ - int cellX = -1; + public int cellX = -1; /** * Indicates the Y position of the associated cell. */ - int cellY = -1; + public int cellY = -1; /** * Indicates the X cell span. */ - int spanX = 1; + public int spanX = 1; /** * Indicates the Y cell span. @@ -80,17 +90,17 @@ public class ItemInfo { /** * Indicates the minimum X cell span. */ - int minSpanX = 1; + public int minSpanX = 1; /** * Indicates the minimum Y cell span. */ - int minSpanY = 1; + public int minSpanY = 1; /** * Indicates that this item needs to be updated in the db */ - boolean requiresDbUpdate = false; + public boolean requiresDbUpdate = false; /** * Title of the item @@ -98,14 +108,28 @@ public class ItemInfo { CharSequence title; /** + * Content description of the item. + */ + CharSequence contentDescription; + + /** * The position of the item in a drag-and-drop operation. */ int[] dropPos = null; + UserHandleCompat user; + ItemInfo() { + user = UserHandleCompat.myUserHandle(); } ItemInfo(ItemInfo info) { + copyFrom(info); + // tempdebug: + LauncherModel.checkItemInfo(this); + } + + public void copyFrom(ItemInfo info) { id = info.id; cellX = info.cellX; cellY = info.cellY; @@ -114,24 +138,22 @@ public class ItemInfo { screenId = info.screenId; itemType = info.itemType; container = info.container; - // tempdebug: - LauncherModel.checkItemInfo(this); - } - - protected Intent getIntent() { - throw new RuntimeException("Unexpected Intent"); + user = info.user; + contentDescription = info.contentDescription; } - protected Intent getRestoredIntent() { + public Intent getIntent() { throw new RuntimeException("Unexpected Intent"); } /** * Write the fields of this item to the DB * + * @param context A context object to use for getting UserManagerCompat * @param values */ - void onAddToDatabase(ContentValues values) { + + void onAddToDatabase(Context context, ContentValues values) { values.put(LauncherSettings.BaseLauncherColumns.ITEM_TYPE, itemType); values.put(LauncherSettings.Favorites.CONTAINER, container); values.put(LauncherSettings.Favorites.SCREEN, screenId); @@ -139,6 +161,13 @@ public class ItemInfo { values.put(LauncherSettings.Favorites.CELLY, cellY); values.put(LauncherSettings.Favorites.SPANX, spanX); values.put(LauncherSettings.Favorites.SPANY, spanY); + long serialNumber = UserManagerCompat.getInstance(context).getSerialNumberForUser(user); + values.put(LauncherSettings.Favorites.PROFILE_ID, serialNumber); + + if (screenId == Workspace.EXTRA_EMPTY_SCREEN_ID) { + // We should never persist an item on the extra empty screen. + throw new RuntimeException("Screen id should not be EXTRA_EMPTY_SCREEN_ID"); + } } void updateValuesWithCoordinates(ContentValues values, int cellX, int cellY) { @@ -182,6 +211,7 @@ public class ItemInfo { public String toString() { return "Item(id=" + this.id + " type=" + this.itemType + " container=" + this.container + " screen=" + screenId + " cellX=" + cellX + " cellY=" + cellY + " spanX=" + spanX - + " spanY=" + spanY + " dropPos=" + dropPos + ")"; + + " spanY=" + spanY + " dropPos=" + Arrays.toString(dropPos) + + " user=" + user + ")"; } } diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index c22a6bf3f..42ec4fb48 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -22,11 +22,13 @@ import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.animation.PropertyValuesHolder; +import android.animation.TimeInterpolator; import android.animation.ValueAnimator; -import android.animation.ValueAnimator.AnimatorUpdateListener; +import android.annotation.TargetApi; import android.app.Activity; import android.app.ActivityManager; import android.app.ActivityOptions; +import android.app.AlertDialog; import android.app.SearchManager; import android.appwidget.AppWidgetHostView; import android.appwidget.AppWidgetManager; @@ -37,6 +39,7 @@ import android.content.ComponentCallbacks2; import android.content.ComponentName; import android.content.ContentResolver; import android.content.Context; +import android.content.DialogInterface; import android.content.Intent; import android.content.IntentFilter; import android.content.SharedPreferences; @@ -44,25 +47,25 @@ import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; -import android.content.pm.ResolveInfo; import android.content.res.Configuration; import android.content.res.Resources; import android.database.ContentObserver; import android.graphics.Bitmap; import android.graphics.Canvas; +import android.graphics.Color; import android.graphics.Point; import android.graphics.PorterDuff; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.AsyncTask; +import android.os.Build; import android.os.Bundle; import android.os.Environment; import android.os.Handler; import android.os.Message; import android.os.StrictMode; import android.os.SystemClock; -import android.provider.Settings; import android.speech.RecognizerIntent; import android.text.Selection; import android.text.SpannableStringBuilder; @@ -70,6 +73,7 @@ import android.text.TextUtils; import android.text.method.TextKeyListener; import android.util.DisplayMetrics; import android.util.Log; +import android.view.ContextThemeWrapper; import android.view.Display; import android.view.Gravity; import android.view.HapticFeedbackConstants; @@ -81,13 +85,16 @@ import android.view.Surface; import android.view.View; import android.view.View.OnClickListener; import android.view.View.OnLongClickListener; +import android.view.ViewAnimationUtils; import android.view.ViewGroup; import android.view.ViewTreeObserver; import android.view.ViewTreeObserver.OnGlobalLayoutListener; +import android.view.Window; import android.view.WindowManager; import android.view.accessibility.AccessibilityEvent; -import android.view.animation.AccelerateDecelerateInterpolator; +import android.view.animation.AccelerateInterpolator; import android.view.animation.DecelerateInterpolator; +import android.view.animation.Interpolator; import android.view.inputmethod.InputMethodManager; import android.widget.Advanceable; import android.widget.FrameLayout; @@ -96,6 +103,14 @@ import android.widget.TextView; import android.widget.Toast; import com.android.launcher3.DropTarget.DragObject; +import com.android.launcher3.PagedView.PageSwitchListener; +import com.android.launcher3.compat.AppWidgetManagerCompat; +import com.android.launcher3.compat.LauncherActivityInfoCompat; +import com.android.launcher3.compat.LauncherAppsCompat; +import com.android.launcher3.compat.PackageInstallerCompat; +import com.android.launcher3.compat.PackageInstallerCompat.PackageInstallInfo; +import com.android.launcher3.compat.UserHandleCompat; +import com.android.launcher3.compat.UserManagerCompat; import java.io.DataInputStream; import java.io.DataOutputStream; @@ -105,6 +120,9 @@ import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintWriter; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.text.DateFormat; import java.util.ArrayList; import java.util.Collection; @@ -113,13 +131,12 @@ import java.util.HashMap; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; - /** * Default launcher application. */ public class Launcher extends Activity implements View.OnClickListener, OnLongClickListener, LauncherModel.Callbacks, - View.OnTouchListener { + View.OnTouchListener, PageSwitchListener, LauncherProviderChangeListener { static final String TAG = "Launcher"; static final boolean LOGD = false; @@ -133,12 +150,12 @@ public class Launcher extends Activity private static final int REQUEST_CREATE_SHORTCUT = 1; private static final int REQUEST_CREATE_APPWIDGET = 5; - private static final int REQUEST_PICK_APPLICATION = 6; private static final int REQUEST_PICK_SHORTCUT = 7; private static final int REQUEST_PICK_APPWIDGET = 9; private static final int REQUEST_PICK_WALLPAPER = 10; private static final int REQUEST_BIND_APPWIDGET = 11; + private static final int REQUEST_RECONFIGURE_APPWIDGET = 12; /** * IntentStarter uses request codes starting with this. This must be greater than all activity @@ -189,9 +206,13 @@ public class Launcher extends Activity // Type: int[] private static final String RUNTIME_STATE_VIEW_IDS = "launcher.view_ids"; - + static final String INTRO_SCREEN_DISMISSED = "launcher.intro_screen_dismissed"; static final String FIRST_RUN_ACTIVITY_DISPLAYED = "launcher.first_run_activity_displayed"; + static final String FIRST_LOAD_COMPLETE = "launcher.first_load_complete"; + static final String ACTION_FIRST_LOAD_COMPLETE = + "com.android.launcher3.action.FIRST_LOAD_COMPLETE"; + private static final String TOOLBAR_ICON_METADATA_NAME = "com.android.launcher.toolbar_icon"; private static final String TOOLBAR_SEARCH_ICON_METADATA_NAME = "com.android.launcher.toolbar_search_icon"; @@ -208,10 +229,12 @@ public class Launcher extends Activity private State mState = State.WORKSPACE; private AnimatorSet mStateAnimation; + private boolean mIsSafeModeEnabled; + static final int APPWIDGET_HOST_ID = 1024; public static final int EXIT_SPRINGLOADED_MODE_SHORT_TIMEOUT = 300; - public static final int EXIT_SPRINGLOADED_MODE_SHORT_TIMEOUT_FOLDER_CLOSE = 400; private static final int ON_ACTIVITY_RESULT_ANIMATION_DELAY = 500; + private static final int ACTIVITY_START_DELAY = 1000; private static final Object sLock = new Object(); private static int sScreen = DEFAULT_SCREEN; @@ -223,6 +246,7 @@ public class Launcher extends Activity private static int NEW_APPS_PAGE_MOVE_DELAY = 500; private static int NEW_APPS_ANIMATION_INACTIVE_TIMEOUT_SECONDS = 5; private static int NEW_APPS_ANIMATION_DELAY = 500; + private static final int SINGLE_FRAME_DELAY = 16; private final BroadcastReceiver mCloseSystemDialogsReceiver = new CloseSystemDialogsIntentReceiver(); @@ -236,9 +260,8 @@ public class Launcher extends Activity private DragLayer mDragLayer; private DragController mDragController; private View mWeightWatcher; - private LauncherClings mLauncherClings; - private AppWidgetManager mAppWidgetManager; + private AppWidgetManagerCompat mAppWidgetManager; private LauncherAppWidgetHost mAppWidgetHost; private ItemInfo mPendingAddInfo = new ItemInfo(); @@ -278,9 +301,6 @@ public class Launcher extends Activity private ArrayList<Runnable> mBindOnResumeCallbacks = new ArrayList<Runnable>(); private ArrayList<Runnable> mOnResumeCallbacks = new ArrayList<Runnable>(); - // Keep track of whether the user has left launcher - private static boolean sPausedFromUserAction = false; - private Bundle mSavedInstanceState; private LauncherModel mModel; @@ -312,10 +332,6 @@ public class Launcher extends Activity // External icons saved in case of resource changes, orientation, etc. private static Drawable.ConstantState[] sGlobalSearchIcon = new Drawable.ConstantState[2]; private static Drawable.ConstantState[] sVoiceSearchIcon = new Drawable.ConstantState[2]; - private static Drawable.ConstantState[] sAppMarketIcon = new Drawable.ConstantState[2]; - - private Intent mAppMarketIntent = null; - private static final boolean DISABLE_MARKET_BUTTON = true; private Drawable mWorkspaceBackgroundDrawable; @@ -352,8 +368,7 @@ public class Launcher extends Activity } }; - private static ArrayList<PendingAddArguments> sPendingAddList - = new ArrayList<PendingAddArguments>(); + private static PendingAddArguments sPendingAddItem; public static boolean sForceEnableRotation = isPropertyEnabled(FORCE_ENABLE_ROTATION_PROPERTY); @@ -364,10 +379,13 @@ public class Launcher extends Activity long screenId; int cellX; int cellY; + int appWidgetId; } private Stats mStats; + FocusIndicatorView mFocusHandler; + static boolean isPropertyEnabled(String propertyName) { return Log.isLoggable(propertyName, Log.VERBOSE); } @@ -393,7 +411,7 @@ public class Launcher extends Activity LauncherAppState.setApplicationContext(getApplicationContext()); LauncherAppState app = LauncherAppState.getInstance(); - + LauncherAppState.getLauncherProvider().setLauncherProviderChangeListener(this); // Determine the dynamic grid properties Point smallestSize = new Point(); Point largestSize = new Point(); @@ -414,16 +432,16 @@ public class Launcher extends Activity // the LauncherApplication should call this, but in case of Instrumentation it might not be present yet mSharedPrefs = getSharedPreferences(LauncherAppState.getSharedPreferencesKey(), Context.MODE_PRIVATE); + mIsSafeModeEnabled = getPackageManager().isSafeMode(); mModel = app.setLauncher(this); mIconCache = app.getIconCache(); mIconCache.flushInvalidIcons(grid); mDragController = new DragController(this); - mLauncherClings = new LauncherClings(this); mInflater = getLayoutInflater(); mStats = new Stats(this); - mAppWidgetManager = AppWidgetManager.getInstance(this); + mAppWidgetManager = AppWidgetManagerCompat.getInstance(this); mAppWidgetHost = new LauncherAppWidgetHost(this, APPWIDGET_HOST_ID); mAppWidgetHost.startListening(); @@ -438,7 +456,6 @@ public class Launcher extends Activity Environment.getExternalStorageDirectory() + "/launcher"); } - checkForLocaleChange(); setContentView(R.layout.launcher); @@ -457,7 +474,7 @@ public class Launcher extends Activity } if (!mRestoring) { - if (DISABLE_SYNCHRONOUS_BINDING_CURRENT_PAGE || sPausedFromUserAction) { + if (DISABLE_SYNCHRONOUS_BINDING_CURRENT_PAGE) { // If the user leaves launcher, then we should just load items asynchronously when // they return. mModel.startLoader(true, PagedView.INVALID_RESTORE_PAGE); @@ -480,25 +497,16 @@ public class Launcher extends Activity // On large interfaces, we want the screen to auto-rotate based on the current orientation unlockScreenOrientation(true); - // The two first run cling paths are mutually exclusive, if the launcher is preinstalled - // on the device, then we always show the first run cling experience (or if there is no - // launcher2). Otherwise, we prompt the user upon started for migration - showFirstRunActivity(); - if (mLauncherClings.shouldShowFirstRunOrMigrationClings()) { - if (mModel.canMigrateFromOldLauncherDb(this)) { - mLauncherClings.showMigrationCling(); - } else { - mLauncherClings.showFirstRunCling(); - } + if (shouldShowIntroScreen()) { + showIntroScreen(); } else { - mLauncherClings.removeFirstRunAndMigrationClings(); + showFirstRunActivity(); + showFirstRunClings(); } } - protected void onUserLeaveHint() { - super.onUserLeaveHint(); - sPausedFromUserAction = true; - } + @Override + public void onLauncherProviderChange() { } /** To be overriden by subclasses to hint to Launcher that we have custom content */ protected boolean hasCustomContentToLeft() { @@ -514,21 +522,6 @@ public class Launcher extends Activity } /** - * To be overridden by subclasses to indicate that there is an activity to launch - * before showing the standard launcher experience. - */ - protected boolean hasFirstRunActivity() { - return false; - } - - /** - * To be overridden by subclasses to launch any first run activity - */ - protected Intent getFirstRunActivity() { - return null; - } - - /** * Invoked by subclasses to signal a change to the {@link #addCustomContentToLeft} value to * ensure the custom content page is added or removed if necessary. */ @@ -552,11 +545,7 @@ public class Launcher extends Activity boolean voiceVisible = false; // If we have a saved version of these external icons, we load them up immediately int coi = getCurrentOrientationIndexForGlobalIcons(); - if (sGlobalSearchIcon[coi] == null || sVoiceSearchIcon[coi] == null || - sAppMarketIcon[coi] == null) { - if (!DISABLE_MARKET_BUTTON) { - updateAppMarketIcon(); - } + if (sGlobalSearchIcon[coi] == null || sVoiceSearchIcon[coi] == null) { searchVisible = updateGlobalSearchIcon(); voiceVisible = updateVoiceSearchIcon(searchVisible); } @@ -568,9 +557,6 @@ public class Launcher extends Activity updateVoiceSearchIcon(sVoiceSearchIcon[coi]); voiceVisible = true; } - if (!DISABLE_MARKET_BUTTON && sAppMarketIcon[coi] != null) { - updateAppMarketIcon(sAppMarketIcon[coi]); - } if (mSearchDropTargetBar != null) { mSearchDropTargetBar.onSearchPackagesChanged(searchVisible, voiceVisible); } @@ -703,19 +689,20 @@ public class Launcher extends Activity } } - /** - * Copied from View -- the View version of the method isn't called - * anywhere else in our process and only exists for API level 17+, - * so it's ok to keep our own version with no API requirement. - */ public static int generateViewId() { - for (;;) { - final int result = sNextGeneratedId.get(); - // aapt-generated IDs have the high byte nonzero; clamp to the range under that. - int newValue = result + 1; - if (newValue > 0x00FFFFFF) newValue = 1; // Roll over to 1, not 0. - if (sNextGeneratedId.compareAndSet(result, newValue)) { - return result; + if (Build.VERSION.SDK_INT >= 17) { + return View.generateViewId(); + } else { + // View.generateViewId() is not available. The following fallback logic is a copy + // of its implementation. + for (;;) { + final int result = sNextGeneratedId.get(); + // aapt-generated IDs have the high byte nonzero; clamp to the range under that. + int newValue = result + 1; + if (newValue > 0x00FFFFFF) newValue = 1; // Roll over to 1, not 0. + if (sNextGeneratedId.compareAndSet(result, newValue)) { + return result; + } } } } @@ -735,40 +722,39 @@ public class Launcher extends Activity * Returns whether we should delay spring loaded mode -- for shortcuts and widgets that have * a configuration step, this allows the proper animations to run after other transitions. */ - private boolean completeAdd(PendingAddArguments args) { - boolean result = false; + private long completeAdd(PendingAddArguments args) { + long screenId = args.screenId; + if (args.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) { + // When the screen id represents an actual screen (as opposed to a rank) we make sure + // that the drop page actually exists. + screenId = ensurePendingDropLayoutExists(args.screenId); + } + switch (args.requestCode) { - case REQUEST_PICK_APPLICATION: - completeAddApplication(args.intent, args.container, args.screenId, args.cellX, - args.cellY); - break; - case REQUEST_PICK_SHORTCUT: - processShortcut(args.intent); - break; case REQUEST_CREATE_SHORTCUT: - completeAddShortcut(args.intent, args.container, args.screenId, args.cellX, + completeAddShortcut(args.intent, args.container, screenId, args.cellX, args.cellY); - result = true; break; case REQUEST_CREATE_APPWIDGET: - int appWidgetId = args.intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1); - completeAddAppWidget(appWidgetId, args.container, args.screenId, null, null); - result = true; + completeAddAppWidget(args.appWidgetId, args.container, screenId, null, null); + break; + case REQUEST_RECONFIGURE_APPWIDGET: + completeRestoreAppWidget(args.appWidgetId); break; } // Before adding this resetAddInfo(), after a shortcut was added to a workspace screen, // if you turned the screen off and then back while in All Apps, Launcher would not // return to the workspace. Clearing mAddInfo.container here fixes this issue resetAddInfo(); - return result; + return screenId; } @Override protected void onActivityResult( final int requestCode, final int resultCode, final Intent data) { // Reset the startActivity waiting flag - mWaitingForResult = false; - int pendingAddWidgetId = mPendingAddWidgetId; + setWaitingForResult(false); + final int pendingAddWidgetId = mPendingAddWidgetId; mPendingAddWidgetId = -1; Runnable exitSpringLoaded = new Runnable() { @@ -784,7 +770,7 @@ public class Launcher extends Activity data.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1) : -1; if (resultCode == RESULT_CANCELED) { completeTwoStageWidgetDrop(RESULT_CANCELED, appWidgetId); - mWorkspace.removeExtraEmptyScreen(true, exitSpringLoaded, + mWorkspace.removeExtraEmptyScreenDelayed(true, exitSpringLoaded, ON_ACTIVITY_RESULT_ANIMATION_DELAY, false); } else if (resultCode == RESULT_OK) { addAppWidgetImpl(appWidgetId, mPendingAddInfo, null, @@ -801,6 +787,7 @@ public class Launcher extends Activity boolean isWidgetDrop = (requestCode == REQUEST_PICK_APPWIDGET || requestCode == REQUEST_CREATE_APPWIDGET); + final boolean workspaceLocked = isWorkspaceLocked(); // We have special handling for widgets if (isWidgetDrop) { final int appWidgetId; @@ -813,33 +800,66 @@ public class Launcher extends Activity } final int result; - final Runnable onComplete; if (appWidgetId < 0 || resultCode == RESULT_CANCELED) { - Log.e(TAG, "Error: appWidgetId (EXTRA_APPWIDGET_ID) was not returned from the \\" + - "widget configuration activity."); + Log.e(TAG, "Error: appWidgetId (EXTRA_APPWIDGET_ID) was not " + + "returned from the widget configuration activity."); result = RESULT_CANCELED; completeTwoStageWidgetDrop(result, appWidgetId); - onComplete = new Runnable() { + final Runnable onComplete = new Runnable() { @Override public void run() { exitSpringLoadedDragModeDelayed(false, 0, null); } }; + if (workspaceLocked) { + // No need to remove the empty screen if we're mid-binding, as the + // the bind will not add the empty screen. + mWorkspace.postDelayed(onComplete, ON_ACTIVITY_RESULT_ANIMATION_DELAY); + } else { + mWorkspace.removeExtraEmptyScreenDelayed(true, onComplete, + ON_ACTIVITY_RESULT_ANIMATION_DELAY, false); + } } else { - result = resultCode; - final CellLayout dropLayout = - (CellLayout) mWorkspace.getScreenWithId(mPendingAddInfo.screenId); - dropLayout.setDropPending(true); - onComplete = new Runnable() { - @Override - public void run() { - completeTwoStageWidgetDrop(result, appWidgetId); - dropLayout.setDropPending(false); + if (!workspaceLocked) { + if (mPendingAddInfo.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) { + // When the screen id represents an actual screen (as opposed to a rank) + // we make sure that the drop page actually exists. + mPendingAddInfo.screenId = + ensurePendingDropLayoutExists(mPendingAddInfo.screenId); } - }; + final CellLayout dropLayout = mWorkspace.getScreenWithId(mPendingAddInfo.screenId); + + dropLayout.setDropPending(true); + final Runnable onComplete = new Runnable() { + @Override + public void run() { + completeTwoStageWidgetDrop(resultCode, appWidgetId); + dropLayout.setDropPending(false); + } + }; + mWorkspace.removeExtraEmptyScreenDelayed(true, onComplete, + ON_ACTIVITY_RESULT_ANIMATION_DELAY, false); + } else { + PendingAddArguments args = preparePendingAddArgs(requestCode, data, appWidgetId, + mPendingAddInfo); + sPendingAddItem = args; + } + } + return; + } + + if (requestCode == REQUEST_RECONFIGURE_APPWIDGET) { + if (resultCode == RESULT_OK) { + // Update the widget view. + PendingAddArguments args = preparePendingAddArgs(requestCode, data, + pendingAddWidgetId, mPendingAddInfo); + if (workspaceLocked) { + sPendingAddItem = args; + } else { + completeAdd(args); + } } - mWorkspace.removeExtraEmptyScreen(true, onComplete, ON_ACTIVITY_RESULT_ANIMATION_DELAY, - false); + // Leave the widget in the pending state if the user canceled the configure. return; } @@ -849,27 +869,54 @@ public class Launcher extends Activity // For example, the user would PICK_SHORTCUT for "Music playlist", and we // launch over to the Music app to actually CREATE_SHORTCUT. if (resultCode == RESULT_OK && mPendingAddInfo.container != ItemInfo.NO_ID) { - final PendingAddArguments args = new PendingAddArguments(); - args.requestCode = requestCode; - args.intent = data; - args.container = mPendingAddInfo.container; - args.screenId = mPendingAddInfo.screenId; - args.cellX = mPendingAddInfo.cellX; - args.cellY = mPendingAddInfo.cellY; + final PendingAddArguments args = preparePendingAddArgs(requestCode, data, -1, + mPendingAddInfo); if (isWorkspaceLocked()) { - sPendingAddList.add(args); + sPendingAddItem = args; } else { completeAdd(args); + mWorkspace.removeExtraEmptyScreenDelayed(true, exitSpringLoaded, + ON_ACTIVITY_RESULT_ANIMATION_DELAY, false); } - mWorkspace.removeExtraEmptyScreen(true, exitSpringLoaded, - ON_ACTIVITY_RESULT_ANIMATION_DELAY, false); } else if (resultCode == RESULT_CANCELED) { - mWorkspace.removeExtraEmptyScreen(true, exitSpringLoaded, + mWorkspace.removeExtraEmptyScreenDelayed(true, exitSpringLoaded, ON_ACTIVITY_RESULT_ANIMATION_DELAY, false); } mDragLayer.clearAnimatedView(); } + private PendingAddArguments preparePendingAddArgs(int requestCode, Intent data, int + appWidgetId, ItemInfo info) { + PendingAddArguments args = new PendingAddArguments(); + args.requestCode = requestCode; + args.intent = data; + args.container = info.container; + args.screenId = info.screenId; + args.cellX = info.cellX; + args.cellY = info.cellY; + args.appWidgetId = appWidgetId; + return args; + } + + /** + * Check to see if a given screen id exists. If not, create it at the end, return the new id. + * + * @param screenId the screen id to check + * @return the new screen, or screenId if it exists + */ + private long ensurePendingDropLayoutExists(long screenId) { + CellLayout dropLayout = + (CellLayout) mWorkspace.getScreenWithId(screenId); + if (dropLayout == null) { + // it's possible that the add screen was removed because it was + // empty and a re-bind occurred + mWorkspace.addExtraEmptyScreen(); + return mWorkspace.commitExtraEmptyScreen(); + } else { + return screenId; + } + } + private void completeTwoStageWidgetDrop(final int resultCode, final int appWidgetId) { CellLayout cellLayout = (CellLayout) mWorkspace.getScreenWithId(mPendingAddInfo.screenId); @@ -938,9 +985,8 @@ public class Launcher extends Activity setWorkspaceBackground(mState == State.WORKSPACE); mPaused = false; - sPausedFromUserAction = false; if (mRestoring || mOnResumeNeedsLoad) { - mWorkspaceLoading = true; + setWorkspaceLoading(true); mModel.startLoader(true, PagedView.INVALID_RESTORE_PAGE); mRestoring = false; mOnResumeNeedsLoad = false; @@ -981,10 +1027,6 @@ public class Launcher extends Activity // Resets the previous workspace icon press state mWaitingForResume.setStayPressed(false); } - if (mAppsCustomizeContent != null) { - // Resets the previous all apps icon press state - mAppsCustomizeContent.resetDrawableState(); - } // It is possible that widgets can receive updates while launcher is not in the foreground. // Consequently, the widgets will be inflated in the orientation of the foreground activity @@ -1010,17 +1052,20 @@ public class Launcher extends Activity // It is also poassible that onShow will instead be called slightly after first layout // if PagedView#setRestorePage was set to the custom content page in onCreate(). if (mWorkspace.isOnOrMovingToCustomContent()) { - mWorkspace.getCustomContentCallbacks().onShow(); + mWorkspace.getCustomContentCallbacks().onShow(true); } } mWorkspace.updateInteractionForState(); mWorkspace.onResume(); + + PackageInstallerCompat.getInstance(this).onResume(); } @Override protected void onPause() { // Ensure that items added to Launcher are queued until Launcher returns InstallShortcutReceiver.enableInstallQueue(); + PackageInstallerCompat.getInstance(this).onPause(); super.onPause(); mPaused = true; @@ -1054,23 +1099,24 @@ public class Launcher extends Activity } public interface CustomContentCallbacks { - // Custom content is completely shown - public void onShow(); + // Custom content is completely shown. {@code fromResume} indicates whether this was caused + // by a onResume or by scrolling otherwise. + public void onShow(boolean fromResume); // Custom content is completely hidden public void onHide(); // Custom content scroll progress changed. From 0 (not showing) to 1 (fully showing). public void onScrollProgressChanged(float progress); + + // Indicates whether the user is allowed to scroll away from the custom content. + boolean isScrollingAllowed(); } protected boolean hasSettings() { return false; } - protected void startSettings() { - } - public interface QSBScroller { public void setScrollY(int scrollY); } @@ -1089,7 +1135,9 @@ public class Launcher extends Activity @Override public Object onRetainNonConfigurationInstance() { // Flag the loader to stop early before switching - mModel.stopLoader(); + if (mModel.isCurrentCallbacks(this)) { + mModel.stopLoader(); + } if (mAppsCustomizeContent != null) { mAppsCustomizeContent.surrender(); } @@ -1196,7 +1244,7 @@ public class Launcher extends Activity mPendingAddInfo.spanY = savedState.getInt(RUNTIME_STATE_PENDING_ADD_SPAN_Y); mPendingAddWidgetInfo = savedState.getParcelable(RUNTIME_STATE_PENDING_ADD_WIDGET_INFO); mPendingAddWidgetId = savedState.getInt(RUNTIME_STATE_PENDING_ADD_WIDGET_ID); - mWaitingForResult = true; + setWaitingForResult(true); mRestoring = true; } @@ -1231,8 +1279,10 @@ public class Launcher extends Activity final DragController dragController = mDragController; mLauncherView = findViewById(R.id.launcher); + mFocusHandler = (FocusIndicatorView) findViewById(R.id.focus_indicator); mDragLayer = (DragLayer) findViewById(R.id.drag_layer); mWorkspace = (Workspace) mDragLayer.findViewById(R.id.workspace); + mWorkspace.setPageSwitchListener(this); mPageIndicators = mDragLayer.findViewById(R.id.page_indicator); mLauncherView.setSystemUiVisibility( @@ -1255,7 +1305,7 @@ public class Launcher extends Activity @Override public void onClick(View arg0) { if (!mWorkspace.isSwitchingState()) { - showAllApps(true, AppsCustomizePagedView.ContentType.Widgets, true); + onClickAddWidgetButton(arg0); } } }); @@ -1266,7 +1316,7 @@ public class Launcher extends Activity @Override public void onClick(View arg0) { if (!mWorkspace.isSwitchingState()) { - startWallpaper(); + onClickWallpaperPicker(arg0); } } }); @@ -1278,9 +1328,9 @@ public class Launcher extends Activity @Override public void onClick(View arg0) { if (!mWorkspace.isSwitchingState()) { - startSettings(); - } + onClickSettingsButton(arg0); } + } }); settingsButton.setOnTouchListener(getHapticFeedbackTouchListener()); } else { @@ -1334,6 +1384,17 @@ public class Launcher extends Activity } /** + * Sets the all apps button. This method is called from {@link Hotseat}. + */ + public void setAllAppsButton(View allAppsButton) { + mAllAppsButton = allAppsButton; + } + + public View getAllAppsButton() { + return mAllAppsButton; + } + + /** * Creates a view representing a shortcut. * * @param info The data structure describing the shortcut. @@ -1356,44 +1417,13 @@ public class Launcher extends Activity */ View createShortcut(int layoutResId, ViewGroup parent, ShortcutInfo info) { BubbleTextView favorite = (BubbleTextView) mInflater.inflate(layoutResId, parent, false); - favorite.applyFromShortcutInfo(info, mIconCache); + favorite.applyFromShortcutInfo(info, mIconCache, true); favorite.setOnClickListener(this); + favorite.setOnFocusChangeListener(mFocusHandler); return favorite; } /** - * Add an application shortcut to the workspace. - * - * @param data The intent describing the application. - * @param cellInfo The position on screen where to create the shortcut. - */ - void completeAddApplication(Intent data, long container, long screenId, int cellX, int cellY) { - final int[] cellXY = mTmpAddItemCellCoordinates; - final CellLayout layout = getCellLayout(container, screenId); - - // First we check if we already know the exact location where we want to add this item. - if (cellX >= 0 && cellY >= 0) { - cellXY[0] = cellX; - cellXY[1] = cellY; - } else if (!layout.findCellForSpan(cellXY, 1, 1)) { - showOutOfSpaceMessage(isHotseatLayout(layout)); - return; - } - - final ShortcutInfo info = mModel.getShortcutInfo(getPackageManager(), data, this); - - if (info != null) { - info.setActivity(this, data.getComponent(), Intent.FLAG_ACTIVITY_NEW_TASK | - Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); - info.container = ItemInfo.NO_ID; - mWorkspace.addApplicationShortcut(info, layout, container, screenId, cellXY[0], cellXY[1], - isWorkspaceLocked(), cellX, cellY); - } else { - Log.e(TAG, "Couldn't find ActivityInfo for selected application: " + data); - } - } - - /** * Add a shortcut to the workspace. * * @param data The intent describing the shortcut. @@ -1543,6 +1573,7 @@ public class Launcher extends Activity launcherInfo.spanY = spanXY[1]; launcherInfo.minSpanX = mPendingAddInfo.minSpanX; launcherInfo.minSpanY = mPendingAddInfo.minSpanY; + launcherInfo.user = mAppWidgetManager.getUser(appWidgetInfo); LauncherModel.addItemToDatabase(this, launcherInfo, container, screenId, cellXY[0], cellXY[1], false); @@ -1595,6 +1626,9 @@ public class Launcher extends Activity mModel.startLoader(false, PagedView.INVALID_RESTORE_PAGE, LauncherModel.LOADER_FLAG_CLEAR_WORKSPACE | LauncherModel.LOADER_FLAG_MIGRATE_SHORTCUTS); + } else if (LauncherAppsCompat.ACTION_MANAGED_PROFILE_ADDED.equals(action) + || LauncherAppsCompat.ACTION_MANAGED_PROFILE_REMOVED.equals(action)) { + getModel().forceReload(); } } }; @@ -1607,16 +1641,61 @@ public class Launcher extends Activity final IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_SCREEN_OFF); filter.addAction(Intent.ACTION_USER_PRESENT); + // For handling managed profiles + filter.addAction(LauncherAppsCompat.ACTION_MANAGED_PROFILE_ADDED); + filter.addAction(LauncherAppsCompat.ACTION_MANAGED_PROFILE_REMOVED); if (ENABLE_DEBUG_INTENTS) { filter.addAction(DebugIntents.DELETE_DATABASE); filter.addAction(DebugIntents.MIGRATE_DATABASE); } registerReceiver(mReceiver, filter); FirstFrameAnimatorHelper.initializeDrawListener(getWindow().getDecorView()); + setupTransparentSystemBarsForLmp(); mAttached = true; mVisible = true; } + /** + * Sets up transparent navigation and status bars in LMP. + * This method is a no-op for other platform versions. + */ + @TargetApi(19) + private void setupTransparentSystemBarsForLmp() { + // TODO(sansid): use the APIs directly when compiling against L sdk. + // Currently we use reflection to access the flags and the API to set the transparency + // on the System bars. + if (Utilities.isLmpOrAbove()) { + try { + getWindow().getAttributes().systemUiVisibility |= + (View.SYSTEM_UI_FLAG_LAYOUT_STABLE + | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN + | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION); + getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS + | WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION); + Field drawsSysBackgroundsField = WindowManager.LayoutParams.class.getField( + "FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS"); + getWindow().addFlags(drawsSysBackgroundsField.getInt(null)); + + Method setStatusBarColorMethod = + Window.class.getDeclaredMethod("setStatusBarColor", int.class); + Method setNavigationBarColorMethod = + Window.class.getDeclaredMethod("setNavigationBarColor", int.class); + setStatusBarColorMethod.invoke(getWindow(), Color.TRANSPARENT); + setNavigationBarColorMethod.invoke(getWindow(), Color.TRANSPARENT); + } catch (NoSuchFieldException e) { + Log.w(TAG, "NoSuchFieldException while setting up transparent bars"); + } catch (NoSuchMethodException ex) { + Log.w(TAG, "NoSuchMethodException while setting up transparent bars"); + } catch (IllegalAccessException e) { + Log.w(TAG, "IllegalAccessException while setting up transparent bars"); + } catch (IllegalArgumentException e) { + Log.w(TAG, "IllegalArgumentException while setting up transparent bars"); + } catch (InvocationTargetException e) { + Log.w(TAG, "InvocationTargetException while setting up transparent bars"); + } finally {} + } + } + @Override public void onDetachedFromWindow() { super.onDetachedFromWindow(); @@ -1667,11 +1746,6 @@ public class Launcher extends Activity } }); } - // When Launcher comes back to foreground, a different Activity might be responsible for - // the app market intent, so refresh the icon - if (!DISABLE_MARKET_BUTTON) { - updateAppMarketIcon(); - } clearTypedText(); } } @@ -1778,10 +1852,6 @@ public class Launcher extends Activity return mModel; } - public LauncherClings getLauncherClings() { - return mLauncherClings; - } - protected SharedPreferences getSharedPrefs() { return mSharedPrefs; } @@ -1790,7 +1860,7 @@ public class Launcher extends Activity getWindow().closeAllPanels(); // Whatever we were doing is hereby canceled. - mWaitingForResult = false; + setWaitingForResult(false); } @Override @@ -1930,8 +2000,13 @@ public class Launcher extends Activity // Stop callbacks from LauncherModel LauncherAppState app = (LauncherAppState.getInstance()); - mModel.stopLoader(); - app.setLauncher(null); + + // It's possible to receive onDestroy after a new Launcher activity has + // been created. In this case, don't interfere with the new Launcher. + if (mModel.isCurrentCallbacks(this)) { + mModel.stopLoader(); + app.setLauncher(null); + } try { mAppWidgetHost.stopListening(); @@ -1959,6 +2034,7 @@ public class Launcher extends Activity mWorkspace = null; mDragController = null; + PackageInstallerCompat.getInstance(this).onStop(); LauncherAnimUtils.onDestroyActivity(); } @@ -1968,7 +2044,9 @@ public class Launcher extends Activity @Override public void startActivityForResult(Intent intent, int requestCode) { - if (requestCode >= 0) mWaitingForResult = true; + if (requestCode >= 0) { + setWaitingForResult(true); + } super.startActivityForResult(intent, requestCode); } @@ -1995,14 +2073,25 @@ public class Launcher extends Activity sourceBounds = mSearchDropTargetBar.getSearchBarBounds(); } - startSearch(initialQuery, selectInitialQuery, + boolean clearTextImmediately = startSearch(initialQuery, selectInitialQuery, appSearchData, sourceBounds); + if (clearTextImmediately) { + clearTypedText(); + } } - public void startSearch(String initialQuery, + /** + * Start a text search. + * + * @return {@code true} if the search will start immediately, so any further keypresses + * will be handled directly by the search UI. {@code false} if {@link Launcher} should continue + * to buffer keypresses. + */ + public boolean startSearch(String initialQuery, boolean selectInitialQuery, Bundle appSearchData, Rect sourceBounds) { startGlobalSearch(initialQuery, selectInitialQuery, appSearchData, sourceBounds); + return false; } /** @@ -2082,6 +2171,24 @@ public class Launcher extends Activity return mWorkspaceLoading; } + private void setWorkspaceLoading(boolean value) { + boolean isLocked = isWorkspaceLocked(); + mWorkspaceLoading = value; + if (isLocked != isWorkspaceLocked()) { + onWorkspaceLockedChanged(); + } + } + + private void setWaitingForResult(boolean value) { + boolean isLocked = isWorkspaceLocked(); + mWaitingForResult = value; + if (isLocked != isWorkspaceLocked()) { + onWorkspaceLockedChanged(); + } + } + + protected void onWorkspaceLockedChanged() { } + private void resetAddInfo() { mPendingAddInfo.container = ItemInfo.NO_ID; mPendingAddInfo.screenId = -1; @@ -2104,10 +2211,9 @@ public class Launcher extends Activity mPendingAddWidgetId = appWidgetId; // Launch over to configure widget, if needed - Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_CONFIGURE); - intent.setComponent(appWidgetInfo.configure); - intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId); - Utilities.startActivityForResultSafely(this, intent, REQUEST_CREATE_APPWIDGET); + mAppWidgetManager.startConfigActivity(appWidgetInfo, appWidgetId, this, + mAppWidgetHost, REQUEST_CREATE_APPWIDGET); + } else { // Otherwise just add it Runnable onComplete = new Runnable() { @@ -2120,7 +2226,7 @@ public class Launcher extends Activity }; completeAddAppWidget(appWidgetId, info.container, info.screenId, boundWidget, appWidgetInfo); - mWorkspace.removeExtraEmptyScreen(true, onComplete, delay, false); + mWorkspace.removeExtraEmptyScreenDelayed(true, onComplete, delay, false); } } @@ -2191,14 +2297,8 @@ public class Launcher extends Activity appWidgetId = getAppWidgetHost().allocateAppWidgetId(); Bundle options = info.bindOptions; - boolean success = false; - if (options != null) { - success = mAppWidgetManager.bindAppWidgetIdIfAllowed(appWidgetId, - info.componentName, options); - } else { - success = mAppWidgetManager.bindAppWidgetIdIfAllowed(appWidgetId, - info.componentName); - } + boolean success = mAppWidgetManager.bindAppWidgetIdIfAllowed( + appWidgetId, info.info, options); if (success) { addAppWidgetImpl(appWidgetId, info, null, info.info); } else { @@ -2206,6 +2306,8 @@ public class Launcher extends Activity Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_BIND); intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId); intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_PROVIDER, info.componentName); + mAppWidgetManager.getUser(mPendingAddWidgetInfo) + .addToIntent(intent, AppWidgetManager.EXTRA_APPWIDGET_PROVIDER_PROFILE); // TODO: we need to make sure that this accounts for the options bundle. // intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_OPTIONS, options); startActivityForResult(intent, REQUEST_BIND_APPWIDGET); @@ -2214,21 +2316,7 @@ public class Launcher extends Activity } void processShortcut(Intent intent) { - // Handle case where user selected "Applications" - String applicationName = getResources().getString(R.string.group_applications); - String shortcutName = intent.getStringExtra(Intent.EXTRA_SHORTCUT_NAME); - - if (applicationName != null && applicationName.equals(shortcutName)) { - Intent mainIntent = new Intent(Intent.ACTION_MAIN, null); - mainIntent.addCategory(Intent.CATEGORY_LAUNCHER); - - Intent pickIntent = new Intent(Intent.ACTION_PICK_ACTIVITY); - pickIntent.putExtra(Intent.EXTRA_INTENT, mainIntent); - pickIntent.putExtra(Intent.EXTRA_TITLE, getText(R.string.title_select_application)); - Utilities.startActivityForResultSafely(this, pickIntent, REQUEST_PICK_APPLICATION); - } else { - Utilities.startActivityForResultSafely(this, intent, REQUEST_CREATE_SHORTCUT); - } + Utilities.startActivityForResultSafely(this, intent, REQUEST_CREATE_SHORTCUT); } void processWallpaper(Intent intent) { @@ -2260,12 +2348,6 @@ public class Launcher extends Activity sFolders.remove(folder.id); } - protected void startWallpaper() { - final Intent pickWallpaper = new Intent(Intent.ACTION_SET_WALLPAPER); - pickWallpaper.setComponent(getWallpaperPickerComponent()); - startActivityForResult(pickWallpaper, REQUEST_PICK_WALLPAPER); - } - protected ComponentName getWallpaperPickerComponent() { return new ComponentName(getPackageName(), LauncherWallpaperPickerActivity.class.getName()); } @@ -2369,59 +2451,63 @@ public class Launcher extends Activity Object tag = v.getTag(); if (tag instanceof ShortcutInfo) { - // Open shortcut - final ShortcutInfo shortcut = (ShortcutInfo) tag; - final Intent intent = shortcut.intent; - - // Check for special shortcuts - if (intent.getComponent() != null) { - final String shortcutClass = intent.getComponent().getClassName(); - - if (shortcutClass.equals(WidgetAdder.class.getName())) { - onClickAddWidgetButton(); - return; - } else if (shortcutClass.equals(MemoryDumpActivity.class.getName())) { - MemoryDumpActivity.startDump(this); - return; - } else if (shortcutClass.equals(ToggleWeightWatcher.class.getName())) { - toggleShowWeightWatcher(); - return; - } - } - - // Start activities - int[] pos = new int[2]; - v.getLocationOnScreen(pos); - intent.setSourceBounds(new Rect(pos[0], pos[1], - pos[0] + v.getWidth(), pos[1] + v.getHeight())); - - boolean success = startActivitySafely(v, intent, tag); - - mStats.recordLaunch(intent, shortcut); - - if (success && v instanceof BubbleTextView) { - mWaitingForResume = (BubbleTextView) v; - mWaitingForResume.setStayPressed(true); - } + onClickAppShortcut(v); } else if (tag instanceof FolderInfo) { if (v instanceof FolderIcon) { - FolderIcon fi = (FolderIcon) v; - handleFolderClick(fi); + onClickFolderIcon(v); } } else if (v == mAllAppsButton) { - if (isAllAppsVisible()) { - showWorkspace(true); - } else { - onClickAllAppsButton(v); + onClickAllAppsButton(v); + } else if (tag instanceof AppInfo) { + startAppShortcutOrInfoActivity(v); + } else if (tag instanceof LauncherAppWidgetInfo) { + if (v instanceof PendingAppWidgetHostView) { + onClickPendingWidget((PendingAppWidgetHostView) v); } } } + public void onClickPagedViewIcon(View v) { + startAppShortcutOrInfoActivity(v); + } + public boolean onTouch(View v, MotionEvent event) { return false; } /** + * Event handler for the app widget view which has not fully restored. + */ + public void onClickPendingWidget(final PendingAppWidgetHostView v) { + final LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) v.getTag(); + if (v.isReadyForClickSetup()) { + int widgetId = info.appWidgetId; + AppWidgetProviderInfo appWidgetInfo = mAppWidgetManager.getAppWidgetInfo(widgetId); + if (appWidgetInfo != null) { + mPendingAddWidgetInfo = appWidgetInfo; + mPendingAddInfo.copyFrom(info); + mPendingAddWidgetId = widgetId; + + AppWidgetManagerCompat.getInstance(this).startConfigActivity(appWidgetInfo, + info.appWidgetId, this, mAppWidgetHost, REQUEST_RECONFIGURE_APPWIDGET); + } + } else if (info.installProgress < 0) { + // The install has not been queued + final String packageName = info.providerName.getPackageName(); + showBrokenAppInstallDialog(packageName, + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + startActivitySafely(v, LauncherModel.getMarketIntent(packageName), info); + } + }); + } else { + // Download has started. + final String packageName = info.providerName.getPackageName(); + startActivitySafely(v, LauncherModel.getMarketIntent(packageName), info); + } + } + + /** * Event handler for the search button * * @param v The view that was clicked. @@ -2467,18 +2553,180 @@ public class Launcher extends Activity * * @param v The view that was clicked. */ - public void onClickAllAppsButton(View v) { - showAllApps(true, AppsCustomizePagedView.ContentType.Applications, false); + protected void onClickAllAppsButton(View v) { + if (LOGD) Log.d(TAG, "onClickAllAppsButton"); + if (isAllAppsVisible()) { + showWorkspace(true); + } else { + showAllApps(true, AppsCustomizePagedView.ContentType.Applications, false); + } + } + + private void showBrokenAppInstallDialog(final String packageName, + DialogInterface.OnClickListener onSearchClickListener) { + new AlertDialog.Builder(new ContextThemeWrapper(this, android.R.style.Theme_DeviceDefault)) + .setTitle(R.string.abandoned_promises_title) + .setMessage(R.string.abandoned_promise_explanation) + .setPositiveButton(R.string.abandoned_search, onSearchClickListener) + .setNeutralButton(R.string.abandoned_clean_this, + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + final UserHandleCompat user = UserHandleCompat.myUserHandle(); + mWorkspace.removeAbandonedPromise(packageName, user); + } + }) + .create().show(); + return; + } + + /** + * Event handler for an app shortcut click. + * + * @param v The view that was clicked. Must be a tagged with a {@link ShortcutInfo}. + */ + protected void onClickAppShortcut(final View v) { + if (LOGD) Log.d(TAG, "onClickAppShortcut"); + Object tag = v.getTag(); + if (!(tag instanceof ShortcutInfo)) { + throw new IllegalArgumentException("Input must be a Shortcut"); + } + + // Open shortcut + final ShortcutInfo shortcut = (ShortcutInfo) tag; + final Intent intent = shortcut.intent; + + // Check for special shortcuts + if (intent.getComponent() != null) { + final String shortcutClass = intent.getComponent().getClassName(); + + if (shortcutClass.equals(MemoryDumpActivity.class.getName())) { + MemoryDumpActivity.startDump(this); + return; + } else if (shortcutClass.equals(ToggleWeightWatcher.class.getName())) { + toggleShowWeightWatcher(); + return; + } + } + + // Check for abandoned promise + if ((v instanceof BubbleTextView) + && shortcut.isPromise() + && !shortcut.hasStatusFlag(ShortcutInfo.FLAG_INSTALL_SESSION_ACTIVE)) { + showBrokenAppInstallDialog( + shortcut.getTargetComponent().getPackageName(), + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + startAppShortcutOrInfoActivity(v); + } + }); + return; + } + + // Start activities + startAppShortcutOrInfoActivity(v); + } + + private void startAppShortcutOrInfoActivity(View v) { + Object tag = v.getTag(); + final ShortcutInfo shortcut; + final Intent intent; + if (tag instanceof ShortcutInfo) { + shortcut = (ShortcutInfo) tag; + intent = shortcut.intent; + int[] pos = new int[2]; + v.getLocationOnScreen(pos); + intent.setSourceBounds(new Rect(pos[0], pos[1], + pos[0] + v.getWidth(), pos[1] + v.getHeight())); + + } else if (tag instanceof AppInfo) { + shortcut = null; + intent = ((AppInfo) tag).intent; + } else { + throw new IllegalArgumentException("Input must be a Shortcut or AppInfo"); + } + + boolean success = startActivitySafely(v, intent, tag); + mStats.recordLaunch(intent, shortcut); + + if (success && v instanceof BubbleTextView) { + mWaitingForResume = (BubbleTextView) v; + mWaitingForResume.setStayPressed(true); + } + } + + /** + * Event handler for a folder icon click. + * + * @param v The view that was clicked. Must be an instance of {@link FolderIcon}. + */ + protected void onClickFolderIcon(View v) { + if (LOGD) Log.d(TAG, "onClickFolder"); + if (!(v instanceof FolderIcon)){ + throw new IllegalArgumentException("Input must be a FolderIcon"); + } + + FolderIcon folderIcon = (FolderIcon) v; + final FolderInfo info = folderIcon.getFolderInfo(); + Folder openFolder = mWorkspace.getFolderForTag(info); + + // If the folder info reports that the associated folder is open, then verify that + // it is actually opened. There have been a few instances where this gets out of sync. + if (info.opened && openFolder == null) { + Log.d(TAG, "Folder info marked as open, but associated folder is not open. Screen: " + + info.screenId + " (" + info.cellX + ", " + info.cellY + ")"); + info.opened = false; + } + + if (!info.opened && !folderIcon.getFolder().isDestroyed()) { + // Close any open folder + closeFolder(); + // Open the requested folder + openFolder(folderIcon); + } else { + // Find the open folder... + int folderScreen; + if (openFolder != null) { + folderScreen = mWorkspace.getPageForView(openFolder); + // .. and close it + closeFolder(openFolder); + if (folderScreen != mWorkspace.getCurrentPage()) { + // Close any folder open on the current screen + closeFolder(); + // Pull the folder onto this screen + openFolder(folderIcon); + } + } + } } /** * Event handler for the (Add) Widgets button that appears after a long press * on the home screen. */ - protected void onClickAddWidgetButton() { + protected void onClickAddWidgetButton(View view) { + if (LOGD) Log.d(TAG, "onClickAddWidgetButton"); showAllApps(true, AppsCustomizePagedView.ContentType.Widgets, true); } + /** + * Event handler for the wallpaper picker button that appears after a long press + * on the home screen. + */ + protected void onClickWallpaperPicker(View v) { + if (LOGD) Log.d(TAG, "onClickWallpaperPicker"); + final Intent pickWallpaper = new Intent(Intent.ACTION_SET_WALLPAPER); + pickWallpaper.setComponent(getWallpaperPickerComponent()); + startActivityForResult(pickWallpaper, REQUEST_PICK_WALLPAPER); + } + + /** + * Event handler for a click on the settings button that appears after a long press + * on the home screen. + */ + protected void onClickSettingsButton(View v) { + if (LOGD) Log.d(TAG, "onClickSettingsButton"); + } + public void onTouchDownAllAppsButton(View v) { // Provide the same haptic feedback that the system offers for virtual keys. v.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY); @@ -2504,15 +2752,7 @@ public class Launcher extends Activity return mHapticFeedbackTouchListener; } - public void onClickAppMarketButton(View v) { - if (!DISABLE_MARKET_BUTTON) { - if (mAppMarketIntent != null) { - startActivitySafely(v, mAppMarketIntent, "app market"); - } else { - Log.e(TAG, "Invalid app market intent."); - } - } - } + public void onDragStarted(View view) {} /** * Called when the user stops interacting with the launcher. @@ -2531,17 +2771,24 @@ public class Launcher extends Activity */ protected void onInteractionBegin() {} - void startApplicationDetailsActivity(ComponentName componentName) { + void startApplicationDetailsActivity(ComponentName componentName, UserHandleCompat user) { String packageName = componentName.getPackageName(); - Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, - Uri.fromParts("package", packageName, null)); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK | - Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); - startActivitySafely(null, intent, "startApplicationDetailsActivity"); + try { + LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(this); + UserManagerCompat userManager = UserManagerCompat.getInstance(this); + launcherApps.showAppDetailsForProfile(componentName, user); + } catch (SecurityException e) { + Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show(); + Log.e(TAG, "Launcher does not have permission to launch settings"); + } catch (ActivityNotFoundException e) { + Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show(); + Log.e(TAG, "Unable to launch settings"); + } } // returns true if the activity was started - boolean startApplicationUninstallActivity(ComponentName componentName, int flags) { + boolean startApplicationUninstallActivity(ComponentName componentName, int flags, + UserHandleCompat user) { if ((flags & AppInfo.DOWNLOADED_FLAG) == 0) { // System applications cannot be installed. For now, show a toast explaining that. // We may give them the option of disabling apps this way. @@ -2555,6 +2802,9 @@ public class Launcher extends Activity Intent.ACTION_DELETE, Uri.fromParts("package", packageName, className)); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); + if (user != null) { + user.addToIntent(intent, Intent.EXTRA_USER); + } startActivity(intent); return true; } @@ -2562,19 +2812,35 @@ public class Launcher extends Activity boolean startActivity(View v, Intent intent, Object tag) { intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - try { // Only launch using the new animation if the shortcut has not opted out (this is a // private contract between launcher and may be ignored in the future). boolean useLaunchAnimation = (v != null) && !intent.hasExtra(INTENT_EXTRA_IGNORE_LAUNCH_ANIMATION); + LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(this); + UserManagerCompat userManager = UserManagerCompat.getInstance(this); + + UserHandleCompat user = null; + if (intent.hasExtra(AppInfo.EXTRA_PROFILE)) { + long serialNumber = intent.getLongExtra(AppInfo.EXTRA_PROFILE, -1); + user = userManager.getUserForSerialNumber(serialNumber); + } + + Bundle optsBundle = null; if (useLaunchAnimation) { - ActivityOptions opts = ActivityOptions.makeScaleUpAnimation(v, 0, 0, - v.getMeasuredWidth(), v.getMeasuredHeight()); + ActivityOptions opts = Utilities.isLmpOrAbove() ? + ActivityOptions.makeCustomAnimation(this, R.anim.task_open_enter, R.anim.no_anim) : + ActivityOptions.makeScaleUpAnimation(v, 0, 0, v.getMeasuredWidth(), v.getMeasuredHeight()); + optsBundle = opts.toBundle(); + } - startActivity(intent, opts.toBundle()); + if (user == null || user.equals(UserHandleCompat.myUserHandle())) { + // Could be launching some bookkeeping activity + startActivity(intent, optsBundle); } else { - startActivity(intent); + // TODO Component can be null when shortcuts are supported for secondary user + launcherApps.startActivityForProfile(intent.getComponent(), user, + intent.getSourceBounds(), optsBundle); } return true; } catch (SecurityException e) { @@ -2589,6 +2855,10 @@ public class Launcher extends Activity boolean startActivitySafely(View v, Intent intent, Object tag) { boolean success = false; + if (mIsSafeModeEnabled && !Utilities.isSystemApp(this, intent)) { + Toast.makeText(this, R.string.safemode_shortcut_error, Toast.LENGTH_SHORT).show(); + return false; + } try { success = startActivity(v, intent, tag); } catch (ActivityNotFoundException e) { @@ -2598,40 +2868,6 @@ public class Launcher extends Activity return success; } - private void handleFolderClick(FolderIcon folderIcon) { - final FolderInfo info = folderIcon.getFolderInfo(); - Folder openFolder = mWorkspace.getFolderForTag(info); - - // If the folder info reports that the associated folder is open, then verify that - // it is actually opened. There have been a few instances where this gets out of sync. - if (info.opened && openFolder == null) { - Log.d(TAG, "Folder info marked as open, but associated folder is not open. Screen: " - + info.screenId + " (" + info.cellX + ", " + info.cellY + ")"); - info.opened = false; - } - - if (!info.opened && !folderIcon.getFolder().isDestroyed()) { - // Close any open folder - closeFolder(); - // Open the requested folder - openFolder(folderIcon); - } else { - // Find the open folder... - int folderScreen; - if (openFolder != null) { - folderScreen = mWorkspace.getPageForView(openFolder); - // .. and close it - closeFolder(openFolder); - if (folderScreen != mWorkspace.getCurrentPage()) { - // Close any folder open on the current screen - closeFolder(); - // Pull the folder onto this screen - openFolder(folderIcon); - } - } - } - } - /** * This method draws the FolderIcon to an ImageView and then adds and positions that ImageView * in the DragLayer in the exact absolute location of the original FolderIcon. @@ -2703,7 +2939,10 @@ public class Launcher extends Activity ObjectAnimator oa = LauncherAnimUtils.ofPropertyValuesHolder(mFolderIconImageView, alpha, scaleX, scaleY); - oa.setDuration(getResources().getInteger(R.integer.config_folderAnimDuration)); + if (Utilities.isLmpOrAbove()) { + oa.setInterpolator(new LogDecelerateInterpolator(100, 0)); + } + oa.setDuration(getResources().getInteger(R.integer.config_folderExpandDuration)); oa.start(); } @@ -2720,7 +2959,7 @@ public class Launcher extends Activity copyFolderIconToImage(fi); ObjectAnimator oa = LauncherAnimUtils.ofPropertyValuesHolder(mFolderIconImageView, alpha, scaleX, scaleY); - oa.setDuration(getResources().getInteger(R.integer.config_folderAnimDuration)); + oa.setDuration(getResources().getInteger(R.integer.config_folderExpandDuration)); oa.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { @@ -2773,9 +3012,6 @@ public class Launcher extends Activity folder.dismissEditingName(); } closeFolder(folder); - - // Dismiss the folder cling - mLauncherClings.dismissFolderCling(null); } } @@ -2808,23 +3044,22 @@ public class Launcher extends Activity } else { return false; } + } else { + return false; } } - if (!(v instanceof CellLayout)) { - v = (View) v.getParent().getParent(); - } - - resetAddInfo(); - CellLayout.CellInfo longClickCellInfo = (CellLayout.CellInfo) v.getTag(); - // This happens when long clicking an item with the dpad/trackball - if (longClickCellInfo == null) { - return true; + CellLayout.CellInfo longClickCellInfo = null; + View itemUnderLongClick = null; + if (v.getTag() instanceof ItemInfo) { + ItemInfo info = (ItemInfo) v.getTag(); + longClickCellInfo = new CellLayout.CellInfo(v, info);; + itemUnderLongClick = longClickCellInfo.cell; + resetAddInfo(); } // The hotseat touch handling does not go through Workspace, and we always allow long press // on hotseat items. - final View itemUnderLongClick = longClickCellInfo.cell; final boolean inHotseat = isHotseatLayout(v); boolean allowLongPress = inHotseat || mWorkspace.allowLongPress(); if (allowLongPress && !mDragController.isDragging()) { @@ -2832,7 +3067,6 @@ public class Launcher extends Activity // User long pressed on empty space mWorkspace.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING); - // Disabling reordering until we sort out some issues. if (mWorkspace.isInOverviewMode()) { mWorkspace.startReordering(v); } else { @@ -2876,22 +3110,12 @@ public class Launcher extends Activity return (mState == State.APPS_CUSTOMIZE) || (mOnResumeState == State.APPS_CUSTOMIZE); } - /** - * Helper method for the cameraZoomIn/cameraZoomOut animations - * @param view The view being animated - * @param scaleFactor The scale factor used for the zoom - */ - private void setPivotsForZoom(View view, float scaleFactor) { - view.setPivotX(view.getWidth() / 2.0f); - view.setPivotY(view.getHeight() / 2.0f); - } - private void setWorkspaceBackground(boolean workspace) { mLauncherView.setBackground(workspace ? mWorkspaceBackgroundDrawable : null); } - void updateWallpaperVisibility(boolean visible) { + protected void changeWallpaperVisiblity(boolean visible) { int wpflags = visible ? WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER : 0; int curflags = getWindow().getAttributes().flags & WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER; @@ -2980,6 +3204,7 @@ public class Launcher extends Activity AppsCustomizePagedView.ContentType contentType = mAppsCustomizeContent.getContentType(); showAppsCustomizeHelper(animated, springLoaded, contentType); } + private void showAppsCustomizeHelper(final boolean animated, final boolean springLoaded, final AppsCustomizePagedView.ContentType contentType) { if (mStateAnimation != null) { @@ -2987,98 +3212,178 @@ public class Launcher extends Activity mStateAnimation.cancel(); mStateAnimation = null; } + + boolean material = Utilities.isLmpOrAbove(); + final Resources res = getResources(); final int duration = res.getInteger(R.integer.config_appsCustomizeZoomInTime); final int fadeDuration = res.getInteger(R.integer.config_appsCustomizeFadeInTime); + final int revealDuration = res.getInteger(R.integer.config_appsCustomizeRevealTime); + final int itemsAlphaStagger = + res.getInteger(R.integer.config_appsCustomizeItemsAlphaStagger); + final float scale = (float) res.getInteger(R.integer.config_appsCustomizeZoomScaleFactor); final View fromView = mWorkspace; final AppsCustomizeTabHost toView = mAppsCustomizeTabHost; - final int startDelay = - res.getInteger(R.integer.config_workspaceAppsCustomizeAnimationStagger); - setPivotsForZoom(toView, scale); + final ArrayList<View> layerViews = new ArrayList<View>(); - // Shrink workspaces away if going to AppsCustomize from workspace + Workspace.State workspaceState = contentType == AppsCustomizePagedView.ContentType.Widgets ? + Workspace.State.OVERVIEW_HIDDEN : Workspace.State.NORMAL_HIDDEN; Animator workspaceAnim = - mWorkspace.getChangeStateAnimation(Workspace.State.SMALL, animated); + mWorkspace.getChangeStateAnimation(workspaceState, animated, layerViews); if (!LauncherAppState.isDisableAllApps() || contentType == AppsCustomizePagedView.ContentType.Widgets) { // Set the content type for the all apps/widgets space mAppsCustomizeTabHost.setContentTypeImmediate(contentType); } - if (animated) { - toView.setScaleX(scale); - toView.setScaleY(scale); - final LauncherViewPropertyAnimator scaleAnim = new LauncherViewPropertyAnimator(toView); - scaleAnim. - scaleX(1f).scaleY(1f). - setDuration(duration). - setInterpolator(new Workspace.ZoomOutInterpolator()); - - toView.setVisibility(View.VISIBLE); - toView.setAlpha(0f); - final ObjectAnimator alphaAnim = LauncherAnimUtils - .ofFloat(toView, "alpha", 0f, 1f) - .setDuration(fadeDuration); - alphaAnim.setInterpolator(new DecelerateInterpolator(1.5f)); - alphaAnim.addUpdateListener(new AnimatorUpdateListener() { - @Override - public void onAnimationUpdate(ValueAnimator animation) { - if (animation == null) { - throw new RuntimeException("animation is null"); - } - float t = (Float) animation.getAnimatedValue(); - dispatchOnLauncherTransitionStep(fromView, t); - dispatchOnLauncherTransitionStep(toView, t); - } - }); + // If for some reason our views aren't initialized, don't animate + boolean initialized = getAllAppsButton() != null; - // toView should appear right at the end of the workspace shrink - // animation + if (animated && initialized) { mStateAnimation = LauncherAnimUtils.createAnimatorSet(); - mStateAnimation.play(scaleAnim).after(startDelay); - mStateAnimation.play(alphaAnim).after(startDelay); + final AppsCustomizePagedView content = (AppsCustomizePagedView) + toView.findViewById(R.id.apps_customize_pane_content); + + final View page = content.getPageAt(content.getCurrentPage()); + final View revealView = toView.findViewById(R.id.fake_page); + + final float initialPanelAlpha = 1f; + + final boolean isWidgetTray = contentType == AppsCustomizePagedView.ContentType.Widgets; + if (isWidgetTray) { + revealView.setBackground(res.getDrawable(R.drawable.quantum_panel_dark)); + } else { + revealView.setBackground(res.getDrawable(R.drawable.quantum_panel)); + } + + // Hide the real page background, and swap in the fake one + content.setPageBackgroundsVisible(false); + revealView.setVisibility(View.VISIBLE); + // We need to hide this view as the animation start will be posted. + revealView.setAlpha(0); + + int width = revealView.getMeasuredWidth(); + int height = revealView.getMeasuredHeight(); + float revealRadius = (float) Math.sqrt((width * width) / 4 + (height * height) / 4); + + revealView.setTranslationY(0); + revealView.setTranslationX(0); + + // Get the y delta between the center of the page and the center of the all apps button + int[] allAppsToPanelDelta = Utilities.getCenterDeltaInScreenSpace(revealView, + getAllAppsButton(), null); + + float alpha = 0; + float xDrift = 0; + float yDrift = 0; + if (material) { + alpha = isWidgetTray ? 0.3f : 1f; + yDrift = isWidgetTray ? height / 2 : allAppsToPanelDelta[1]; + xDrift = isWidgetTray ? 0 : allAppsToPanelDelta[0]; + } else { + yDrift = 2 * height / 3; + xDrift = 0; + } + final float initAlpha = alpha; + + revealView.setLayerType(View.LAYER_TYPE_HARDWARE, null); + layerViews.add(revealView); + PropertyValuesHolder panelAlpha = PropertyValuesHolder.ofFloat("alpha", initAlpha, 1f); + PropertyValuesHolder panelDriftY = + PropertyValuesHolder.ofFloat("translationY", yDrift, 0); + PropertyValuesHolder panelDriftX = + PropertyValuesHolder.ofFloat("translationX", xDrift, 0); + + ObjectAnimator panelAlphaAndDrift = ObjectAnimator.ofPropertyValuesHolder(revealView, + panelAlpha, panelDriftY, panelDriftX); + + panelAlphaAndDrift.setDuration(revealDuration); + panelAlphaAndDrift.setInterpolator(new LogDecelerateInterpolator(100, 0)); + + mStateAnimation.play(panelAlphaAndDrift); + + if (page != null) { + page.setVisibility(View.VISIBLE); + page.setLayerType(View.LAYER_TYPE_HARDWARE, null); + layerViews.add(page); + + ObjectAnimator pageDrift = ObjectAnimator.ofFloat(page, "translationY", yDrift, 0); + page.setTranslationY(yDrift); + pageDrift.setDuration(revealDuration); + pageDrift.setInterpolator(new LogDecelerateInterpolator(100, 0)); + pageDrift.setStartDelay(itemsAlphaStagger); + mStateAnimation.play(pageDrift); + + page.setAlpha(0f); + ObjectAnimator itemsAlpha = ObjectAnimator.ofFloat(page, "alpha", 0f, 1f); + itemsAlpha.setDuration(revealDuration); + itemsAlpha.setInterpolator(new AccelerateInterpolator(1.5f)); + itemsAlpha.setStartDelay(itemsAlphaStagger); + mStateAnimation.play(itemsAlpha); + } + + View pageIndicators = toView.findViewById(R.id.apps_customize_page_indicator); + pageIndicators.setAlpha(0.01f); + ObjectAnimator indicatorsAlpha = + ObjectAnimator.ofFloat(pageIndicators, "alpha", 1f); + indicatorsAlpha.setDuration(revealDuration); + mStateAnimation.play(indicatorsAlpha); + + if (material) { + final View allApps = getAllAppsButton(); + int allAppsButtonSize = LauncherAppState.getInstance(). + getDynamicGrid().getDeviceProfile().allAppsButtonVisualSize; + float startRadius = isWidgetTray ? 0 : allAppsButtonSize / 2; + Animator reveal = ViewAnimationUtils.createCircularReveal(revealView, width / 2, + height / 2, startRadius, revealRadius); + reveal.setDuration(revealDuration); + reveal.setInterpolator(new LogDecelerateInterpolator(100, 0)); + + reveal.addListener(new AnimatorListenerAdapter() { + public void onAnimationStart(Animator animation) { + if (!isWidgetTray) { + allApps.setVisibility(View.INVISIBLE); + } + } + public void onAnimationEnd(Animator animation) { + if (!isWidgetTray) { + allApps.setVisibility(View.VISIBLE); + } + } + }); + mStateAnimation.play(reveal); + } mStateAnimation.addListener(new AnimatorListenerAdapter() { @Override - public void onAnimationStart(Animator animation) { - // Prepare the position - toView.setTranslationX(0.0f); - toView.setTranslationY(0.0f); - toView.setVisibility(View.VISIBLE); - toView.bringToFront(); - } - @Override public void onAnimationEnd(Animator animation) { dispatchOnLauncherTransitionEnd(fromView, animated, false); dispatchOnLauncherTransitionEnd(toView, animated, false); + revealView.setVisibility(View.INVISIBLE); + revealView.setLayerType(View.LAYER_TYPE_NONE, null); + if (page != null) { + page.setLayerType(View.LAYER_TYPE_NONE, null); + } + content.setPageBackgroundsVisible(true); + // Hide the search bar if (mSearchDropTargetBar != null) { mSearchDropTargetBar.hideSearchBar(false); } } + }); if (workspaceAnim != null) { mStateAnimation.play(workspaceAnim); } - boolean delayAnim = false; - dispatchOnLauncherTransitionPrepare(fromView, animated, false); dispatchOnLauncherTransitionPrepare(toView, animated, false); - - // If any of the objects being animated haven't been measured/laid out - // yet, delay the animation until we get a layout pass - if ((((LauncherTransitionable) toView).getContent().getMeasuredWidth() == 0) || - (mWorkspace.getMeasuredWidth() == 0) || - (toView.getMeasuredWidth() == 0)) { - delayAnim = true; - } - final AnimatorSet stateAnimation = mStateAnimation; final Runnable startAnimRunnable = new Runnable() { public void run() { @@ -3086,23 +3391,28 @@ public class Launcher extends Activity // we waited for a layout/draw pass if (mStateAnimation != stateAnimation) return; - setPivotsForZoom(toView, scale); dispatchOnLauncherTransitionStart(fromView, animated, false); dispatchOnLauncherTransitionStart(toView, animated, false); - LauncherAnimUtils.startAnimationAfterNextDraw(mStateAnimation, toView); + + revealView.setAlpha(initAlpha); + if (Utilities.isLmpOrAbove()) { + for (int i = 0; i < layerViews.size(); i++) { + View v = layerViews.get(i); + if (v != null) { + boolean attached = true; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + attached = v.isAttachedToWindow(); + } + if (attached) v.buildLayer(); + } + } + } + mStateAnimation.start(); } }; - if (delayAnim) { - final ViewTreeObserver observer = toView.getViewTreeObserver(); - observer.addOnGlobalLayoutListener(new OnGlobalLayoutListener() { - public void onGlobalLayout() { - startAnimRunnable.run(); - toView.getViewTreeObserver().removeOnGlobalLayoutListener(this); - } - }); - } else { - startAnimRunnable.run(); - } + toView.bringToFront(); + toView.setVisibility(View.VISIBLE); + toView.post(startAnimRunnable); } else { toView.setTranslationX(0.0f); toView.setTranslationY(0.0f); @@ -3139,54 +3449,184 @@ public class Launcher extends Activity mStateAnimation.cancel(); mStateAnimation = null; } + + boolean material = Utilities.isLmpOrAbove(); Resources res = getResources(); final int duration = res.getInteger(R.integer.config_appsCustomizeZoomOutTime); - final int fadeOutDuration = - res.getInteger(R.integer.config_appsCustomizeFadeOutTime); + final int fadeOutDuration = res.getInteger(R.integer.config_appsCustomizeFadeOutTime); + final int revealDuration = res.getInteger(R.integer.config_appsCustomizeConcealTime); + final int itemsAlphaStagger = + res.getInteger(R.integer.config_appsCustomizeItemsAlphaStagger); + final float scaleFactor = (float) res.getInteger(R.integer.config_appsCustomizeZoomScaleFactor); final View fromView = mAppsCustomizeTabHost; final View toView = mWorkspace; Animator workspaceAnim = null; + final ArrayList<View> layerViews = new ArrayList<View>(); + if (toState == Workspace.State.NORMAL) { - int stagger = res.getInteger(R.integer.config_appsCustomizeWorkspaceAnimationStagger); workspaceAnim = mWorkspace.getChangeStateAnimation( - toState, animated, stagger, -1); + toState, animated, layerViews); } else if (toState == Workspace.State.SPRING_LOADED || toState == Workspace.State.OVERVIEW) { workspaceAnim = mWorkspace.getChangeStateAnimation( - toState, animated); - } - - setPivotsForZoom(fromView, scaleFactor); - showHotseat(animated); - if (animated) { - final LauncherViewPropertyAnimator scaleAnim = - new LauncherViewPropertyAnimator(fromView); - scaleAnim. - scaleX(scaleFactor).scaleY(scaleFactor). - setDuration(duration). - setInterpolator(new Workspace.ZoomInInterpolator()); - - final ObjectAnimator alphaAnim = LauncherAnimUtils - .ofFloat(fromView, "alpha", 1f, 0f) - .setDuration(fadeOutDuration); - alphaAnim.setInterpolator(new AccelerateDecelerateInterpolator()); - alphaAnim.addUpdateListener(new AnimatorUpdateListener() { - @Override - public void onAnimationUpdate(ValueAnimator animation) { - float t = 1f - (Float) animation.getAnimatedValue(); - dispatchOnLauncherTransitionStep(fromView, t); - dispatchOnLauncherTransitionStep(toView, t); - } - }); + toState, animated, layerViews); + } + + // If for some reason our views aren't initialized, don't animate + boolean initialized = getAllAppsButton() != null; + if (animated && initialized) { mStateAnimation = LauncherAnimUtils.createAnimatorSet(); + if (workspaceAnim != null) { + mStateAnimation.play(workspaceAnim); + } - dispatchOnLauncherTransitionPrepare(fromView, animated, true); - dispatchOnLauncherTransitionPrepare(toView, animated, true); - mAppsCustomizeContent.stopScrolling(); + final AppsCustomizePagedView content = (AppsCustomizePagedView) + fromView.findViewById(R.id.apps_customize_pane_content); + + final View page = content.getPageAt(content.getNextPage()); + + // We need to hide side pages of the Apps / Widget tray to avoid some ugly edge cases + int count = content.getChildCount(); + for (int i = 0; i < count; i++) { + View child = content.getChildAt(i); + if (child != page) { + child.setVisibility(View.INVISIBLE); + } + } + final View revealView = fromView.findViewById(R.id.fake_page); + + // hideAppsCustomizeHelper is called in some cases when it is already hidden + // don't perform all these no-op animations. In particularly, this was causing + // the all-apps button to pop in and out. + if (fromView.getVisibility() == View.VISIBLE) { + AppsCustomizePagedView.ContentType contentType = content.getContentType(); + final boolean isWidgetTray = + contentType == AppsCustomizePagedView.ContentType.Widgets; + + if (isWidgetTray) { + revealView.setBackground(res.getDrawable(R.drawable.quantum_panel_dark)); + } else { + revealView.setBackground(res.getDrawable(R.drawable.quantum_panel)); + } + + int width = revealView.getMeasuredWidth(); + int height = revealView.getMeasuredHeight(); + float revealRadius = (float) Math.sqrt((width * width) / 4 + (height * height) / 4); + + // Hide the real page background, and swap in the fake one + revealView.setVisibility(View.VISIBLE); + content.setPageBackgroundsVisible(false); + + final View allAppsButton = getAllAppsButton(); + revealView.setTranslationY(0); + int[] allAppsToPanelDelta = Utilities.getCenterDeltaInScreenSpace(revealView, + allAppsButton, null); + + float xDrift = 0; + float yDrift = 0; + if (material) { + yDrift = isWidgetTray ? height / 2 : allAppsToPanelDelta[1]; + xDrift = isWidgetTray ? 0 : allAppsToPanelDelta[0]; + } else { + yDrift = 5 * height / 4; + xDrift = 0; + } + + revealView.setLayerType(View.LAYER_TYPE_HARDWARE, null); + TimeInterpolator decelerateInterpolator = material ? + new LogDecelerateInterpolator(100, 0) : + new LogDecelerateInterpolator(30, 0); + + // The vertical motion of the apps panel should be delayed by one frame + // from the conceal animation in order to give the right feel. We correpsondingly + // shorten the duration so that the slide and conceal end at the same time. + ObjectAnimator panelDriftY = LauncherAnimUtils.ofFloat(revealView, "translationY", + 0, yDrift); + panelDriftY.setDuration(revealDuration - SINGLE_FRAME_DELAY); + panelDriftY.setStartDelay(itemsAlphaStagger + SINGLE_FRAME_DELAY); + panelDriftY.setInterpolator(decelerateInterpolator); + mStateAnimation.play(panelDriftY); + + ObjectAnimator panelDriftX = LauncherAnimUtils.ofFloat(revealView, "translationX", + 0, xDrift); + panelDriftX.setDuration(revealDuration - SINGLE_FRAME_DELAY); + panelDriftX.setStartDelay(itemsAlphaStagger + SINGLE_FRAME_DELAY); + panelDriftX.setInterpolator(decelerateInterpolator); + mStateAnimation.play(panelDriftX); + + if (isWidgetTray || !material) { + float finalAlpha = material ? 0.4f : 0f; + revealView.setAlpha(1f); + ObjectAnimator panelAlpha = LauncherAnimUtils.ofFloat(revealView, "alpha", + 1f, finalAlpha); + panelAlpha.setDuration(revealDuration); + panelAlpha.setInterpolator(material ? decelerateInterpolator : + new AccelerateInterpolator(1.5f)); + mStateAnimation.play(panelAlpha); + } + + if (page != null) { + page.setLayerType(View.LAYER_TYPE_HARDWARE, null); + + ObjectAnimator pageDrift = LauncherAnimUtils.ofFloat(page, "translationY", + 0, yDrift); + page.setTranslationY(0); + pageDrift.setDuration(revealDuration - SINGLE_FRAME_DELAY); + pageDrift.setInterpolator(decelerateInterpolator); + pageDrift.setStartDelay(itemsAlphaStagger + SINGLE_FRAME_DELAY); + mStateAnimation.play(pageDrift); + + page.setAlpha(1f); + ObjectAnimator itemsAlpha = LauncherAnimUtils.ofFloat(page, "alpha", 1f, 0f); + itemsAlpha.setDuration(100); + itemsAlpha.setInterpolator(decelerateInterpolator); + mStateAnimation.play(itemsAlpha); + } + + View pageIndicators = fromView.findViewById(R.id.apps_customize_page_indicator); + pageIndicators.setAlpha(1f); + ObjectAnimator indicatorsAlpha = + LauncherAnimUtils.ofFloat(pageIndicators, "alpha", 0f); + indicatorsAlpha.setDuration(revealDuration); + indicatorsAlpha.setInterpolator(new DecelerateInterpolator(1.5f)); + mStateAnimation.play(indicatorsAlpha); + + width = revealView.getMeasuredWidth(); + + if (material) { + if (!isWidgetTray) { + allAppsButton.setVisibility(View.INVISIBLE); + } + int allAppsButtonSize = LauncherAppState.getInstance(). + getDynamicGrid().getDeviceProfile().allAppsButtonVisualSize; + float finalRadius = isWidgetTray ? 0 : allAppsButtonSize / 2; + Animator reveal = + LauncherAnimUtils.createCircularReveal(revealView, width / 2, + height / 2, revealRadius, finalRadius); + reveal.setInterpolator(new LogDecelerateInterpolator(100, 0)); + reveal.setDuration(revealDuration); + reveal.setStartDelay(itemsAlphaStagger); + + reveal.addListener(new AnimatorListenerAdapter() { + public void onAnimationEnd(Animator animation) { + revealView.setVisibility(View.INVISIBLE); + if (!isWidgetTray) { + allAppsButton.setVisibility(View.VISIBLE); + } + } + }); + + mStateAnimation.play(reveal); + } + + dispatchOnLauncherTransitionPrepare(fromView, animated, true); + dispatchOnLauncherTransitionPrepare(toView, animated, true); + mAppsCustomizeContent.stopScrolling(); + } mStateAnimation.addListener(new AnimatorListenerAdapter() { @Override @@ -3197,17 +3637,57 @@ public class Launcher extends Activity if (onCompleteRunnable != null) { onCompleteRunnable.run(); } + + revealView.setLayerType(View.LAYER_TYPE_NONE, null); + if (page != null) { + page.setLayerType(View.LAYER_TYPE_NONE, null); + } + content.setPageBackgroundsVisible(true); + // Unhide side pages + int count = content.getChildCount(); + for (int i = 0; i < count; i++) { + View child = content.getChildAt(i); + child.setVisibility(View.VISIBLE); + } + + // Reset page transforms + if (page != null) { + page.setTranslationX(0); + page.setTranslationY(0); + page.setAlpha(1); + } + content.setCurrentPage(content.getNextPage()); + mAppsCustomizeContent.updateCurrentPageScroll(); } }); - mStateAnimation.playTogether(scaleAnim, alphaAnim); - if (workspaceAnim != null) { - mStateAnimation.play(workspaceAnim); - } - dispatchOnLauncherTransitionStart(fromView, animated, true); - dispatchOnLauncherTransitionStart(toView, animated, true); - LauncherAnimUtils.startAnimationAfterNextDraw(mStateAnimation, toView); + final AnimatorSet stateAnimation = mStateAnimation; + final Runnable startAnimRunnable = new Runnable() { + public void run() { + // Check that mStateAnimation hasn't changed while + // we waited for a layout/draw pass + if (mStateAnimation != stateAnimation) + return; + dispatchOnLauncherTransitionStart(fromView, animated, false); + dispatchOnLauncherTransitionStart(toView, animated, false); + + if (Utilities.isLmpOrAbove()) { + for (int i = 0; i < layerViews.size(); i++) { + View v = layerViews.get(i); + if (v != null) { + boolean attached = true; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + attached = v.isAttachedToWindow(); + } + if (attached) v.buildLayer(); + } + } + } + mStateAnimation.start(); + } + }; + fromView.post(startAnimRunnable); } else { fromView.setVisibility(View.GONE); dispatchOnLauncherTransitionPrepare(fromView, animated, true); @@ -3236,10 +3716,7 @@ public class Launcher extends Activity } void showWorkspace(boolean animated, Runnable onCompleteRunnable) { - if (mWorkspace.isInOverviewMode()) { - mWorkspace.exitOverviewMode(animated); - } - if (mState != State.WORKSPACE) { + if (mState != State.WORKSPACE || mWorkspace.getState() != Workspace.State.NORMAL) { boolean wasInSpringLoadedMode = (mState != State.WORKSPACE); mWorkspace.setVisibility(View.VISIBLE); hideAppsCustomizeHelper(Workspace.State.NORMAL, animated, false, onCompleteRunnable); @@ -3288,7 +3765,13 @@ public class Launcher extends Activity mAppsCustomizeTabHost.reset(); } showAppsCustomizeHelper(animated, false, contentType); - mAppsCustomizeTabHost.requestFocus(); + mAppsCustomizeTabHost.post(new Runnable() { + @Override + public void run() { + // We post this in-case the all apps view isn't yet constructed. + mAppsCustomizeTabHost.requestFocus(); + } + }); // Change the state *after* we've called all the transition code mState = State.APPS_CUSTOMIZE; @@ -3328,7 +3811,6 @@ public class Launcher extends Activity } } }, delay); - } void exitSpringLoadedDragMode() { @@ -3350,25 +3832,6 @@ public class Launcher extends Activity } /** - * Shows the hotseat area. - */ - void showHotseat(boolean animated) { - if (!LauncherAppState.getInstance().isScreenLarge()) { - if (animated) { - if (mHotseat.getAlpha() != 1f) { - int duration = 0; - if (mSearchDropTargetBar != null) { - duration = mSearchDropTargetBar.getTransitionInDuration(); - } - mHotseat.animate().alpha(1f).setDuration(duration); - } - } else { - mHotseat.setAlpha(1f); - } - } - } - - /** * Hides the hotseat area. */ void hideHotseat(boolean animated) { @@ -3621,44 +4084,6 @@ public class Launcher extends Activity public void disableVoiceButtonProxy(boolean disabled) { updateVoiceButtonProxyVisible(disabled); } - /** - * Sets the app market icon - */ - private void updateAppMarketIcon() { - if (!DISABLE_MARKET_BUTTON) { - final View marketButton = findViewById(R.id.market_button); - Intent intent = new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_APP_MARKET); - // Find the app market activity by resolving an intent. - // (If multiple app markets are installed, it will return the ResolverActivity.) - ComponentName activityName = intent.resolveActivity(getPackageManager()); - if (activityName != null) { - int coi = getCurrentOrientationIndexForGlobalIcons(); - mAppMarketIntent = intent; - sAppMarketIcon[coi] = updateTextButtonWithIconFromExternalActivity( - R.id.market_button, activityName, R.drawable.ic_launcher_market_holo, - TOOLBAR_ICON_METADATA_NAME); - marketButton.setVisibility(View.VISIBLE); - } else { - // We should hide and disable the view so that we don't try and restore the visibility - // of it when we swap between drag & normal states from IconDropTarget subclasses. - marketButton.setVisibility(View.GONE); - marketButton.setEnabled(false); - } - } - } - - private void updateAppMarketIcon(Drawable.ConstantState d) { - if (!DISABLE_MARKET_BUTTON) { - // Ensure that the new drawable we are creating has the approprate toolbar icon bounds - Resources r = getResources(); - Drawable marketIconDrawable = d.newDrawable(r); - int w = r.getDimensionPixelSize(R.dimen.toolbar_external_icon_width); - int h = r.getDimensionPixelSize(R.dimen.toolbar_external_icon_height); - marketIconDrawable.setBounds(0, 0, w, h); - - updateTextButtonWithDrawable(R.id.market_button, marketIconDrawable); - } - } @Override public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { @@ -3667,7 +4092,7 @@ public class Launcher extends Activity text.clear(); // Populate event with a fake title based on the current state. if (mState == State.APPS_CUSTOMIZE) { - text.add(mAppsCustomizeTabHost.getCurrentTabView().getContentDescription()); + text.add(mAppsCustomizeTabHost.getContentTag()); } else { text.add(getString(R.string.all_apps_home_button_label)); } @@ -3775,7 +4200,7 @@ public class Launcher extends Activity * Implementation of the method from LauncherModel.Callbacks. */ public void startBinding() { - mWorkspaceLoading = true; + setWorkspaceLoading(true); // If we're starting binding all over again, clear any bind calls we'd postponed in // the past (see waitUntilResume) -- we don't need them since we're starting binding @@ -3875,7 +4300,7 @@ public class Launcher extends Activity } // Remove the extra empty screen - mWorkspace.removeExtraEmptyScreen(false, null); + mWorkspace.removeExtraEmptyScreen(false, false); if (!LauncherAppState.isDisableAllApps() && addedApps != null && mAppsCustomizeContent != null) { @@ -3926,7 +4351,15 @@ public class Launcher extends Activity if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) { CellLayout cl = mWorkspace.getScreenWithId(item.screenId); if (cl != null && cl.isOccupied(item.cellX, item.cellY)) { - throw new RuntimeException("OCCUPIED"); + View v = cl.getChildAt(item.cellX, item.cellY); + Object tag = v.getTag(); + String desc = "Collision while binding workspace item: " + item + + ". Collides with " + tag; + if (LauncherAppState.isDogfoodBuild()) { + throw (new RuntimeException(desc)); + } else { + Log.d(TAG, desc); + } } } @@ -4021,13 +4454,74 @@ public class Launcher extends Activity } final Workspace workspace = mWorkspace; - final int appWidgetId = item.appWidgetId; - final AppWidgetProviderInfo appWidgetInfo = mAppWidgetManager.getAppWidgetInfo(appWidgetId); - if (DEBUG_WIDGETS) { - Log.d(TAG, "bindAppWidget: id=" + item.appWidgetId + " belongs to component " + appWidgetInfo.provider); + AppWidgetProviderInfo appWidgetInfo; + if (((item.restoreStatus & LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY) == 0) && + ((item.restoreStatus & LauncherAppWidgetInfo.FLAG_ID_NOT_VALID) != 0)) { + + appWidgetInfo = mModel.findAppWidgetProviderInfoWithComponent(this, item.providerName); + if (appWidgetInfo == null) { + if (DEBUG_WIDGETS) { + Log.d(TAG, "Removing restored widget: id=" + item.appWidgetId + + " belongs to component " + item.providerName + + ", as the povider is null"); + } + LauncherModel.deleteItemFromDatabase(this, item); + return; + } + // Note: This assumes that the id remap broadcast is received before this step. + // If that is not the case, the id remap will be ignored and user may see the + // click to setup view. + PendingAddWidgetInfo pendingInfo = new PendingAddWidgetInfo(appWidgetInfo, null, null); + pendingInfo.spanX = item.spanX; + pendingInfo.spanY = item.spanY; + pendingInfo.minSpanX = item.minSpanX; + pendingInfo.minSpanY = item.minSpanY; + Bundle options = + AppsCustomizePagedView.getDefaultOptionsForWidget(this, pendingInfo); + + int newWidgetId = mAppWidgetHost.allocateAppWidgetId(); + boolean success = mAppWidgetManager.bindAppWidgetIdIfAllowed( + newWidgetId, appWidgetInfo, options); + + // TODO consider showing a permission dialog when the widget is clicked. + if (!success) { + mAppWidgetHost.deleteAppWidgetId(newWidgetId); + if (DEBUG_WIDGETS) { + Log.d(TAG, "Removing restored widget: id=" + item.appWidgetId + + " belongs to component " + item.providerName + + ", as the launcher is unable to bing a new widget id"); + } + LauncherModel.deleteItemFromDatabase(this, item); + return; + } + + item.appWidgetId = newWidgetId; + + // If the widget has a configure activity, it is still needs to set it up, otherwise + // the widget is ready to go. + item.restoreStatus = (appWidgetInfo.configure == null) + ? LauncherAppWidgetInfo.RESTORE_COMPLETED + : LauncherAppWidgetInfo.FLAG_UI_NOT_READY; + + LauncherModel.updateItemInDatabase(this, item); } - item.hostView = mAppWidgetHost.createView(this, appWidgetId, appWidgetInfo); + if (item.restoreStatus == LauncherAppWidgetInfo.RESTORE_COMPLETED) { + final int appWidgetId = item.appWidgetId; + appWidgetInfo = mAppWidgetManager.getAppWidgetInfo(appWidgetId); + if (DEBUG_WIDGETS) { + Log.d(TAG, "bindAppWidget: id=" + item.appWidgetId + " belongs to component " + appWidgetInfo.provider); + } + + item.hostView = mAppWidgetHost.createView(this, appWidgetId, appWidgetInfo); + } else { + appWidgetInfo = null; + PendingAppWidgetHostView view = new PendingAppWidgetHostView(this, item); + view.updateIcon(mIconCache); + item.hostView = view; + item.hostView.updateAppWidget(null); + item.hostView.setOnClickListener(this); + } item.hostView.setTag(item); item.onBindAppWidget(this); @@ -4044,6 +4538,26 @@ public class Launcher extends Activity } } + /** + * Restores a pending widget. + * + * @param appWidgetId The app widget id + * @param cellInfo The position on screen where to create the widget. + */ + private void completeRestoreAppWidget(final int appWidgetId) { + LauncherAppWidgetHostView view = mWorkspace.getWidgetForAppWidgetId(appWidgetId); + if ((view == null) || !(view instanceof PendingAppWidgetHostView)) { + Log.e(TAG, "Widget update called, when the widget no longer exists."); + return; + } + + LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) view.getTag(); + info.restoreStatus = LauncherAppWidgetInfo.RESTORE_COMPLETED; + + mWorkspace.reinflateWidgetsIfNecessary(); + LauncherModel.updateItemInDatabase(this, info); + } + public void onPageBoundSynchronously(int page) { mSynchronouslyBoundPages.add(page); } @@ -4071,24 +4585,44 @@ public class Launcher extends Activity mWorkspace.restoreInstanceStateForRemainingPages(); + setWorkspaceLoading(false); + sendLoadingCompleteBroadcastIfNecessary(); + // If we received the result of any pending adds while the loader was running (e.g. the // widget configuration forced an orientation change), process them now. - for (int i = 0; i < sPendingAddList.size(); i++) { - completeAdd(sPendingAddList.get(i)); - } - sPendingAddList.clear(); + if (sPendingAddItem != null) { + final long screenId = completeAdd(sPendingAddItem); - // Update the market app icon as necessary (the other icons will be managed in response to - // package changes in bindSearchablesChanged() - if (!DISABLE_MARKET_BUTTON) { - updateAppMarketIcon(); + // TODO: this moves the user to the page where the pending item was added. Ideally, + // the screen would be guaranteed to exist after bind, and the page would be set through + // the workspace restore process. + mWorkspace.post(new Runnable() { + @Override + public void run() { + mWorkspace.snapToScreenId(screenId); + } + }); + sPendingAddItem = null; } - mWorkspaceLoading = false; if (upgradePath) { mWorkspace.getUniqueComponents(true, null); mIntentsOnWorkspaceFromUpgradePath = mWorkspace.getUniqueComponents(true, null); } + PackageInstallerCompat.getInstance(this).onFinishBind(); + mModel.recheckRestoredItems(this); + } + + private void sendLoadingCompleteBroadcastIfNecessary() { + if (!mSharedPrefs.getBoolean(FIRST_LOAD_COMPLETE, false)) { + String permission = + getResources().getString(R.string.receive_first_load_broadcast_permission); + Intent intent = new Intent(ACTION_FIRST_LOAD_COMPLETE); + sendBroadcast(intent, permission); + SharedPreferences.Editor editor = mSharedPrefs.edit(); + editor.putBoolean(FIRST_LOAD_COMPLETE, true); + editor.apply(); + } } public boolean isAllAppsButtonRank(int rank) { @@ -4176,7 +4710,7 @@ public class Launcher extends Activity } if (mWorkspace != null) { - mWorkspace.updateShortcuts(apps); + mWorkspace.updateShortcutsAndWidgets(apps); } if (!LauncherAppState.isDisableAllApps() && @@ -4186,6 +4720,48 @@ public class Launcher extends Activity } /** + * Packages were restored + */ + public void bindAppsRestored(final ArrayList<AppInfo> apps) { + Runnable r = new Runnable() { + public void run() { + bindAppsRestored(apps); + } + }; + if (waitUntilResume(r)) { + return; + } + + if (mWorkspace != null) { + mWorkspace.updateShortcutsAndWidgets(apps); + } + } + + /** + * Update the state of a package, typically related to install state. + * + * Implementation of the method from LauncherModel.Callbacks. + */ + @Override + public void updatePackageState(ArrayList<PackageInstallInfo> installInfo) { + if (mWorkspace != null) { + mWorkspace.updatePackageState(installInfo); + } + } + + /** + * Update the label and icon of all the icons in a package + * + * Implementation of the method from LauncherModel.Callbacks. + */ + @Override + public void updatePackageBadge(String packageName) { + if (mWorkspace != null) { + mWorkspace.updatePackageBadge(packageName, UserHandleCompat.myUserHandle()); + } + } + + /** * A package was uninstalled. We take both the super set of packageNames * in addition to specific applications to remove, the reason being that * this can be called when a package is updated as well. In that scenario, @@ -4195,10 +4771,10 @@ public class Launcher extends Activity * Implementation of the method from LauncherModel.Callbacks. */ public void bindComponentsRemoved(final ArrayList<String> packageNames, - final ArrayList<AppInfo> appInfos) { + final ArrayList<AppInfo> appInfos, final UserHandleCompat user) { Runnable r = new Runnable() { public void run() { - bindComponentsRemoved(packageNames, appInfos); + bindComponentsRemoved(packageNames, appInfos, user); } }; if (waitUntilResume(r)) { @@ -4206,10 +4782,10 @@ public class Launcher extends Activity } if (!packageNames.isEmpty()) { - mWorkspace.removeItemsByPackageName(packageNames); + mWorkspace.removeItemsByPackageName(packageNames, user); } if (!appInfos.isEmpty()) { - mWorkspace.removeItemsByApplicationInfo(appInfos); + mWorkspace.removeItemsByApplicationInfo(appInfos, user); } // Notify the drag controller @@ -4307,7 +4883,7 @@ public class Launcher extends Activity * @param hint the hint to be displayed in the search bar. */ protected void onSearchBarHintChanged(String hint) { - mLauncherClings.updateSearchBarHint(hint); + } protected boolean isLauncherPreinstalled() { @@ -4325,6 +4901,17 @@ public class Launcher extends Activity } } + /** + * This method indicates whether or not we should suggest default wallpaper dimensions + * when our wallpaper cropper was not yet used to set a wallpaper. + */ + protected boolean overrideWallpaperDimensions() { + return true; + } + + protected boolean shouldClingFocusHotseatApp() { + return false; + } protected String getFirstRunClingSearchBarHint() { return ""; } @@ -4347,23 +4934,19 @@ public class Launcher extends Activity return ""; } - public void dismissFirstRunCling(View v) { - mLauncherClings.dismissFirstRunCling(v); - } - public void dismissMigrationClingCopyApps(View v) { - mLauncherClings.dismissMigrationClingCopyApps(v); - } - public void dismissMigrationClingUseDefault(View v) { - mLauncherClings.dismissMigrationClingUseDefault(v); - } - public void dismissMigrationWorkspaceCling(View v) { - mLauncherClings.dismissMigrationWorkspaceCling(v); - } - public void dismissWorkspaceCling(View v) { - mLauncherClings.dismissWorkspaceCling(v); + /** + * To be overridden by subclasses to indicate that there is an activity to launch + * before showing the standard launcher experience. + */ + protected boolean hasFirstRunActivity() { + return false; } - public void dismissFolderCling(View v) { - mLauncherClings.dismissFolderCling(v); + + /** + * To be overridden by subclasses to launch any first run activity + */ + protected Intent getFirstRunActivity() { + return null; } private boolean shouldRunFirstRunActivity() { @@ -4371,15 +4954,21 @@ public class Launcher extends Activity !mSharedPrefs.getBoolean(FIRST_RUN_ACTIVITY_DISPLAYED, false); } - public void showFirstRunActivity() { + protected boolean hasRunFirstRunActivity() { + return mSharedPrefs.getBoolean(FIRST_RUN_ACTIVITY_DISPLAYED, false); + } + + public boolean showFirstRunActivity() { if (shouldRunFirstRunActivity() && hasFirstRunActivity()) { Intent firstRunIntent = getFirstRunActivity(); if (firstRunIntent != null) { startActivity(firstRunIntent); markFirstRunActivityShown(); + return true; } } + return false; } private void markFirstRunActivityShown() { @@ -4388,6 +4977,77 @@ public class Launcher extends Activity editor.apply(); } + /** + * To be overridden by subclasses to indicate that there is an in-activity full-screen intro + * screen that must be displayed and dismissed. + */ + protected boolean hasDismissableIntroScreen() { + return false; + } + + /** + * Full screen intro screen to be shown and dismissed before the launcher can be used. + */ + protected View getIntroScreen() { + return null; + } + + /** + * To be overriden by subclasses to indicate whether the in-activity intro screen has been + * dismissed. This method is ignored if #hasDismissableIntroScreen returns false. + */ + private boolean shouldShowIntroScreen() { + return hasDismissableIntroScreen() && + !mSharedPrefs.getBoolean(INTRO_SCREEN_DISMISSED, false); + } + + protected void showIntroScreen() { + View introScreen = getIntroScreen(); + changeWallpaperVisiblity(false); + if (introScreen != null) { + mDragLayer.showOverlayView(introScreen); + } + } + + public void dismissIntroScreen() { + markIntroScreenDismissed(); + if (showFirstRunActivity()) { + // We delay hiding the intro view until the first run activity is showing. This + // avoids a blip. + mWorkspace.postDelayed(new Runnable() { + @Override + public void run() { + mDragLayer.dismissOverlayView(); + showFirstRunClings(); + } + }, ACTIVITY_START_DELAY); + } else { + mDragLayer.dismissOverlayView(); + showFirstRunClings(); + } + changeWallpaperVisiblity(true); + } + + private void markIntroScreenDismissed() { + SharedPreferences.Editor editor = mSharedPrefs.edit(); + editor.putBoolean(INTRO_SCREEN_DISMISSED, true); + editor.apply(); + } + + private void showFirstRunClings() { + // The two first run cling paths are mutually exclusive, if the launcher is preinstalled + // on the device, then we always show the first run cling experience (or if there is no + // launcher2). Otherwise, we prompt the user upon started for migration + LauncherClings launcherClings = new LauncherClings(this); + if (launcherClings.shouldShowFirstRunOrMigrationClings()) { + if (mModel.canMigrateFromOldLauncherDb(this)) { + launcherClings.showMigrationCling(); + } else { + launcherClings.showLongPressCling(true); + } + } + } + void showWorkspaceSearchAndHotseat() { if (mWorkspace != null) mWorkspace.setAlpha(1f); if (mHotseat != null) mHotseat.setAlpha(1f); @@ -4402,24 +5062,44 @@ public class Launcher extends Activity if (mSearchDropTargetBar != null) mSearchDropTargetBar.hideSearchBar(false); } - public ItemInfo createAppDragInfo(Intent appLaunchIntent) { - ResolveInfo ri = getPackageManager().resolveActivity(appLaunchIntent, 0); - if (ri == null) { + // Called from search suggestion, not supported in other profiles. + final UserHandleCompat myUser = UserHandleCompat.myUserHandle(); + LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(this); + LauncherActivityInfoCompat activityInfo = launcherApps.resolveActivity(appLaunchIntent, + myUser); + if (activityInfo == null) { return null; } - return new AppInfo(getPackageManager(), ri, mIconCache, null); + return new AppInfo(this, activityInfo, myUser, mIconCache, null); } public ItemInfo createShortcutDragInfo(Intent shortcutIntent, CharSequence caption, Bitmap icon) { - return new ShortcutInfo(shortcutIntent, caption, icon); + // Called from search suggestion, not supported in other profiles. + return createShortcutDragInfo(shortcutIntent, caption, icon, + UserHandleCompat.myUserHandle()); + } + + public ItemInfo createShortcutDragInfo(Intent shortcutIntent, CharSequence caption, + Bitmap icon, UserHandleCompat user) { + UserManagerCompat userManager = UserManagerCompat.getInstance(this); + CharSequence contentDescription = userManager.getBadgedLabelForUser(caption, user); + return new ShortcutInfo(shortcutIntent, caption, contentDescription, icon, user); + } + + protected void moveWorkspaceToDefaultScreen() { + mWorkspace.moveToDefaultScreen(false); } public void startDrag(View dragView, ItemInfo dragInfo, DragSource source) { dragView.setTag(dragInfo); - mWorkspace.onDragStartedWithItem(dragView); - mWorkspace.beginDragShared(dragView, source); + mWorkspace.onExternalDragStartedWithItem(dragView); + mWorkspace.beginExternalDragShared(dragView, source); + } + + @Override + public void onPageSwitch(View newPage, int newPageIndex) { } /** diff --git a/src/com/android/launcher3/LauncherAnimUtils.java b/src/com/android/launcher3/LauncherAnimUtils.java index e6c220b2a..be295f8b3 100644 --- a/src/com/android/launcher3/LauncherAnimUtils.java +++ b/src/com/android/launcher3/LauncherAnimUtils.java @@ -22,6 +22,7 @@ import android.animation.ObjectAnimator; import android.animation.PropertyValuesHolder; import android.animation.ValueAnimator; import android.view.View; +import android.view.ViewAnimationUtils; import android.view.ViewTreeObserver; import java.util.HashSet; @@ -126,4 +127,14 @@ public class LauncherAnimUtils { new FirstFrameAnimatorHelper(anim, view); return anim; } + + public static Animator createCircularReveal(View view, int centerX, + int centerY, float startRadius, float endRadius) { + Animator anim = ViewAnimationUtils.createCircularReveal(view, centerX, + centerY, startRadius, endRadius); + if (anim instanceof ValueAnimator) { + new FirstFrameAnimatorHelper((ValueAnimator) anim, view); + } + return anim; + } } diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java index 29e18f9c0..246278fa2 100644 --- a/src/com/android/launcher3/LauncherAppState.java +++ b/src/com/android/launcher3/LauncherAppState.java @@ -17,19 +17,29 @@ package com.android.launcher3; import android.app.SearchManager; -import android.content.*; +import android.content.ComponentName; +import android.content.ContentResolver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; import android.content.res.Configuration; import android.content.res.Resources; import android.database.ContentObserver; import android.os.Handler; import android.util.Log; +import com.android.launcher3.compat.LauncherAppsCompat; +import com.android.launcher3.compat.PackageInstallerCompat.PackageInstallInfo; + import java.lang.ref.WeakReference; +import java.util.ArrayList; public class LauncherAppState implements DeviceProfile.DeviceProfileCallbacks { private static final String TAG = "LauncherAppState"; private static final String SHARED_PREFERENCES_KEY = "com.android.launcher3.prefs"; + private static final boolean DEBUG = false; + private final AppFilter mAppFilter; private final BuildInfo mBuildInfo; private LauncherModel mModel; @@ -90,16 +100,11 @@ public class LauncherAppState implements DeviceProfile.DeviceProfileCallbacks { mAppFilter = AppFilter.loadByName(sContext.getString(R.string.app_filter_class)); mBuildInfo = BuildInfo.loadByName(sContext.getString(R.string.build_info_class)); mModel = new LauncherModel(this, mIconCache, mAppFilter); + final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(sContext); + launcherApps.addOnAppsChangedCallback(mModel); // Register intent receivers - IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED); - filter.addAction(Intent.ACTION_PACKAGE_REMOVED); - filter.addAction(Intent.ACTION_PACKAGE_CHANGED); - filter.addDataScheme("package"); - sContext.registerReceiver(mModel, filter); - filter = new IntentFilter(); - filter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE); - filter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE); + IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_LOCALE_CHANGED); filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED); sContext.registerReceiver(mModel, filter); @@ -115,7 +120,7 @@ public class LauncherAppState implements DeviceProfile.DeviceProfileCallbacks { resolver.registerContentObserver(LauncherSettings.Favorites.CONTENT_URI, true, mFavoritesObserver); } - + public void recreateWidgetPreviewDb() { if (mWidgetPreviewCacheDb != null) { mWidgetPreviewCacheDb.close(); @@ -128,6 +133,8 @@ public class LauncherAppState implements DeviceProfile.DeviceProfileCallbacks { */ public void onTerminate() { sContext.unregisterReceiver(mModel); + final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(sContext); + launcherApps.removeOnAppsChangedCallback(mModel); ContentResolver resolver = sContext.getContentResolver(); resolver.unregisterContentObserver(mFavoritesObserver); @@ -154,7 +161,7 @@ public class LauncherAppState implements DeviceProfile.DeviceProfileCallbacks { return mModel; } - IconCache getIconCache() { + public IconCache getIconCache() { return mIconCache; } @@ -249,4 +256,15 @@ public class LauncherAppState implements DeviceProfile.DeviceProfileCallbacks { public static boolean isDogfoodBuild() { return getInstance().mBuildInfo.isDogfoodBuild(); } + + public void setPackageState(ArrayList<PackageInstallInfo> installInfo) { + mModel.setPackageState(installInfo); + } + + /** + * Updates the icons and label of all icons for the provided package name. + */ + public void updatePackageBadge(String packageName) { + mModel.updatePackageBadge(packageName); + } } diff --git a/src/com/android/launcher3/LauncherAppWidgetHost.java b/src/com/android/launcher3/LauncherAppWidgetHost.java index 7b08d4403..a309f268c 100644 --- a/src/com/android/launcher3/LauncherAppWidgetHost.java +++ b/src/com/android/launcher3/LauncherAppWidgetHost.java @@ -20,6 +20,9 @@ import android.appwidget.AppWidgetHost; import android.appwidget.AppWidgetHostView; import android.appwidget.AppWidgetProviderInfo; import android.content.Context; +import android.os.TransactionTooLargeException; + +import java.util.ArrayList; /** * Specific {@link AppWidgetHost} that creates our {@link LauncherAppWidgetHostView} @@ -28,6 +31,8 @@ import android.content.Context; */ public class LauncherAppWidgetHost extends AppWidgetHost { + private final ArrayList<Runnable> mProviderChangeListeners = new ArrayList<Runnable>(); + Launcher mLauncher; public LauncherAppWidgetHost(Launcher launcher, int hostId) { @@ -42,14 +47,42 @@ public class LauncherAppWidgetHost extends AppWidgetHost { } @Override + public void startListening() { + try { + super.startListening(); + } catch (Exception e) { + if (e.getCause() instanceof TransactionTooLargeException) { + // We're willing to let this slide. The exception is being caused by the list of + // RemoteViews which is being passed back. The startListening relationship will + // have been established by this point, and we will end up populating the + // widgets upon bind anyway. See issue 14255011 for more context. + } else { + throw new RuntimeException(e); + } + } + } + + @Override public void stopListening() { super.stopListening(); clearViews(); } + public void addProviderChangeListener(Runnable callback) { + mProviderChangeListeners.add(callback); + } + + public void removeProviderChangeListener(Runnable callback) { + mProviderChangeListeners.remove(callback); + } + protected void onProvidersChanged() { // Once we get the message that widget packages are updated, we need to rebind items // in AppsCustomize accordingly. mLauncher.bindPackagesUpdated(LauncherModel.getSortedWidgetsAndShortcuts(mLauncher)); + + for (Runnable callback : mProviderChangeListeners) { + callback.run(); + } } } diff --git a/src/com/android/launcher3/LauncherAppWidgetHostView.java b/src/com/android/launcher3/LauncherAppWidgetHostView.java index 51a649a07..e39727b17 100644 --- a/src/com/android/launcher3/LauncherAppWidgetHostView.java +++ b/src/com/android/launcher3/LauncherAppWidgetHostView.java @@ -21,6 +21,7 @@ import android.content.Context; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; +import android.view.ViewConfiguration; import android.view.ViewGroup; import android.widget.RemoteViews; @@ -30,12 +31,16 @@ import com.android.launcher3.DragLayer.TouchCompleteListener; * {@inheritDoc} */ public class LauncherAppWidgetHostView extends AppWidgetHostView implements TouchCompleteListener { + + LayoutInflater mInflater; + private CheckLongPressHelper mLongPressHelper; - private LayoutInflater mInflater; private Context mContext; private int mPreviousOrientation; private DragLayer mDragLayer; + private float mSlop; + public LauncherAppWidgetHostView(Context context) { super(context); mContext = context; @@ -56,7 +61,8 @@ public class LauncherAppWidgetHostView extends AppWidgetHostView implements Touc super.updateAppWidget(remoteViews); } - public boolean orientationChangedSincedInflation() { + public boolean isReinflateRequired() { + // Re-inflate is required if the orientation has changed since last inflated. int orientation = mContext.getResources().getConfiguration().orientation; if (mPreviousOrientation != orientation) { return true; @@ -90,6 +96,11 @@ public class LauncherAppWidgetHostView extends AppWidgetHostView implements Touc case MotionEvent.ACTION_CANCEL: mLongPressHelper.cancelLongPress(); break; + case MotionEvent.ACTION_MOVE: + if (!Utilities.pointInView(this, ev.getX(), ev.getY(), mSlop)) { + mLongPressHelper.cancelLongPress(); + } + break; } // Otherwise continue letting touch events fall through to children @@ -104,11 +115,22 @@ public class LauncherAppWidgetHostView extends AppWidgetHostView implements Touc case MotionEvent.ACTION_CANCEL: mLongPressHelper.cancelLongPress(); break; + case MotionEvent.ACTION_MOVE: + if (!Utilities.pointInView(this, ev.getX(), ev.getY(), mSlop)) { + mLongPressHelper.cancelLongPress(); + } + break; } return false; } @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + mSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop(); + } + + @Override public void cancelLongPress() { super.cancelLongPress(); mLongPressHelper.cancelLongPress(); diff --git a/src/com/android/launcher3/LauncherAppWidgetInfo.java b/src/com/android/launcher3/LauncherAppWidgetInfo.java index 28df90fb0..5c6535a24 100644 --- a/src/com/android/launcher3/LauncherAppWidgetInfo.java +++ b/src/com/android/launcher3/LauncherAppWidgetInfo.java @@ -19,11 +19,36 @@ package com.android.launcher3; import android.appwidget.AppWidgetHostView; import android.content.ComponentName; import android.content.ContentValues; +import android.content.Context; + +import com.android.launcher3.compat.UserHandleCompat; /** * Represents a widget (either instantiated or about to be) in the Launcher. */ -class LauncherAppWidgetInfo extends ItemInfo { +public class LauncherAppWidgetInfo extends ItemInfo { + + public static final int RESTORE_COMPLETED = 0; + + /** + * This is set during the package backup creation. + */ + public static final int FLAG_ID_NOT_VALID = 1; + + /** + * Indicates that the provider is not available yet. + */ + public static final int FLAG_PROVIDER_NOT_READY = 2; + + /** + * Indicates that the widget UI is not yet ready, and user needs to set it up again. + */ + public static final int FLAG_UI_NOT_READY = 4; + + /** + * Indicates that the widget restore has started. + */ + public static final int FLAG_RESTORE_STARTED = 8; /** * Indicates that the widget hasn't been instantiated yet. @@ -42,6 +67,16 @@ class LauncherAppWidgetInfo extends ItemInfo { int minWidth = -1; int minHeight = -1; + /** + * Indicates the restore status of the widget. + */ + int restoreStatus; + + /** + * Indicates the installation progress of the widget provider + */ + int installProgress = -1; + private boolean mHasNotifiedInitialWidgetSizeChanged; /** @@ -59,13 +94,17 @@ class LauncherAppWidgetInfo extends ItemInfo { // to indicate that they should be calculated based on the layout and minWidth/minHeight spanX = -1; spanY = -1; + // We only support app widgets on current user. + user = UserHandleCompat.myUserHandle(); + restoreStatus = RESTORE_COMPLETED; } @Override - void onAddToDatabase(ContentValues values) { - super.onAddToDatabase(values); + void onAddToDatabase(Context context, ContentValues values) { + super.onAddToDatabase(context, values); values.put(LauncherSettings.Favorites.APPWIDGET_ID, appWidgetId); values.put(LauncherSettings.Favorites.APPWIDGET_PROVIDER, providerName.flattenToString()); + values.put(LauncherSettings.Favorites.RESTORED, restoreStatus); } /** @@ -96,4 +135,12 @@ class LauncherAppWidgetInfo extends ItemInfo { super.unbind(); hostView = null; } + + public final boolean isWidgetIdValid() { + return (restoreStatus & FLAG_ID_NOT_VALID) == 0; + } + + public final boolean hasRestoreFlag(int flag) { + return (restoreStatus & flag) == flag; + } } diff --git a/src/com/android/launcher3/LauncherBackupAgentHelper.java b/src/com/android/launcher3/LauncherBackupAgentHelper.java index de6aedddd..c20c6939d 100644 --- a/src/com/android/launcher3/LauncherBackupAgentHelper.java +++ b/src/com/android/launcher3/LauncherBackupAgentHelper.java @@ -17,13 +17,16 @@ package com.android.launcher3; import android.app.backup.BackupAgentHelper; +import android.app.backup.BackupDataInput; import android.app.backup.BackupManager; -import android.app.backup.SharedPreferencesBackupHelper; import android.content.Context; -import android.content.SharedPreferences; +import android.database.Cursor; +import android.os.ParcelFileDescriptor; import android.provider.Settings; import android.util.Log; +import java.io.IOException; + public class LauncherBackupAgentHelper extends BackupAgentHelper { private static final String TAG = "LauncherBackupAgentHelper"; @@ -54,14 +57,14 @@ public class LauncherBackupAgentHelper extends BackupAgentHelper { // modifies the file outside the normal codepaths, so it looks like another // process. This forces a reload of the file, in case this process persists. String spKey = LauncherAppState.getSharedPreferencesKey(); - SharedPreferences sp = getSharedPreferences(spKey, Context.MODE_MULTI_PROCESS); + getSharedPreferences(spKey, Context.MODE_MULTI_PROCESS); super.onDestroy(); } @Override public void onCreate() { boolean restoreEnabled = 0 != Settings.Secure.getInt( - getContentResolver(), SETTING_RESTORE_ENABLED, 0); + getContentResolver(), SETTING_RESTORE_ENABLED, 1); if (VERBOSE) Log.v(TAG, "restore is " + (restoreEnabled ? "enabled" : "disabled")); addHelper(LauncherBackupHelper.LAUNCHER_PREFS_PREFIX, @@ -71,4 +74,21 @@ public class LauncherBackupAgentHelper extends BackupAgentHelper { addHelper(LauncherBackupHelper.LAUNCHER_PREFIX, new LauncherBackupHelper(this, restoreEnabled)); } + + @Override + public void onRestore(BackupDataInput data, int appVersionCode, ParcelFileDescriptor newState) + throws IOException { + super.onRestore(data, appVersionCode, newState); + + // If no favorite was migrated, clear the data and start fresh. + final Cursor c = getContentResolver().query( + LauncherSettings.Favorites.CONTENT_URI_NO_NOTIFICATION, null, null, null, null); + boolean hasData = c.moveToNext(); + c.close(); + + if (!hasData) { + if (VERBOSE) Log.v(TAG, "Nothing was restored, clearing DB"); + LauncherAppState.getLauncherProvider().createEmptyDB(); + } + } } diff --git a/src/com/android/launcher3/LauncherBackupHelper.java b/src/com/android/launcher3/LauncherBackupHelper.java index 62e6f3102..201f3e9bb 100644 --- a/src/com/android/launcher3/LauncherBackupHelper.java +++ b/src/com/android/launcher3/LauncherBackupHelper.java @@ -28,6 +28,8 @@ import com.android.launcher3.backup.BackupProtos.Key; import com.android.launcher3.backup.BackupProtos.Resource; import com.android.launcher3.backup.BackupProtos.Screen; import com.android.launcher3.backup.BackupProtos.Widget; +import com.android.launcher3.compat.UserManagerCompat; +import com.android.launcher3.compat.UserHandleCompat; import android.app.backup.BackupDataInputStream; import android.app.backup.BackupDataOutput; @@ -108,6 +110,7 @@ public class LauncherBackupHelper implements BackupHelper { Favorites.SPANX, // 14 Favorites.SPANY, // 15 Favorites.TITLE, // 16 + Favorites.PROFILE_ID, // 17 }; private static final int ID_INDEX = 0; @@ -127,6 +130,7 @@ public class LauncherBackupHelper implements BackupHelper { private static final int SPANX_INDEX = 14; private static final int SPANY_INDEX = 15; private static final int TITLE_INDEX = 16; + private static final int PROFILE_ID_INDEX = 17; private static final String[] SCREEN_PROJECTION = { WorkspaceScreens._ID, // 0 @@ -144,11 +148,12 @@ public class LauncherBackupHelper implements BackupHelper { private HashMap<ComponentName, AppWidgetProviderInfo> mWidgetMap; - private ArrayList<Key> mKeys; + private final ArrayList<Key> mKeys; public LauncherBackupHelper(Context context, boolean restoreEnabled) { mContext = context; mRestoreEnabled = restoreEnabled; + mKeys = new ArrayList<Key>(); } private void dataChanged() { @@ -214,9 +219,6 @@ public class LauncherBackupHelper implements BackupHelper { @Override public void restoreEntity(BackupDataInputStream data) { if (VERBOSE) Log.v(TAG, "restoreEntity"); - if (mKeys == null) { - mKeys = new ArrayList<Key>(); - } byte[] buffer = new byte[512]; String backupKey = data.getKey(); int dataSize = data.size(); @@ -297,8 +299,9 @@ public class LauncherBackupHelper implements BackupHelper { // persist things that have changed since the last backup ContentResolver cr = mContext.getContentResolver(); + // Don't backup apps in other profiles for now. Cursor cursor = cr.query(Favorites.CONTENT_URI, FAVORITE_PROJECTION, - null, null, null); + getUserSelectionArg(), null, null); Set<String> currentIds = new HashSet<String>(cursor.getCount()); try { cursor.moveToPosition(-1); @@ -349,7 +352,7 @@ public class LauncherBackupHelper implements BackupHelper { try { ContentResolver cr = mContext.getContentResolver(); ContentValues values = unpackFavorite(buffer, 0, dataSize); - cr.insert(Favorites.CONTENT_URI, values); + cr.insert(Favorites.CONTENT_URI_NO_NOTIFICATION, values); } catch (InvalidProtocolBufferNanoException e) { Log.e(TAG, "failed to decode favorite", e); } @@ -454,14 +457,19 @@ public class LauncherBackupHelper implements BackupHelper { } final ContentResolver cr = mContext.getContentResolver(); final int dpi = mContext.getResources().getDisplayMetrics().densityDpi; + final UserHandleCompat myUserHandle = UserHandleCompat.myUserHandle(); // read the old ID set Set<String> savedIds = getSavedIdsByType(Key.ICON, in); if (DEBUG) Log.d(TAG, "icon savedIds.size()=" + savedIds.size()); + // Don't backup apps in other profiles for now. int startRows = out.rows; if (DEBUG) Log.d(TAG, "starting here: " + startRows); - String where = Favorites.ITEM_TYPE + "=" + Favorites.ITEM_TYPE_APPLICATION; + + String where = "(" + Favorites.ITEM_TYPE + "=" + Favorites.ITEM_TYPE_APPLICATION + " OR " + + Favorites.ITEM_TYPE + "=" + Favorites.ITEM_TYPE_SHORTCUT + ") AND " + + getUserSelectionArg(); Cursor cursor = cr.query(Favorites.CONTENT_URI, FAVORITE_PROJECTION, where, null, null); Set<String> currentIds = new HashSet<String>(cursor.getCount()); @@ -491,9 +499,9 @@ public class LauncherBackupHelper implements BackupHelper { if (DEBUG) Log.d(TAG, "I can count this high: " + out.rows); if ((out.rows - startRows) < MAX_ICONS_PER_PASS) { if (VERBOSE) Log.v(TAG, "saving icon " + backupKey); - Bitmap icon = mIconCache.getIcon(intent); + Bitmap icon = mIconCache.getIcon(intent, myUserHandle); keys.add(key); - if (icon != null && !mIconCache.isDefaultIcon(icon)) { + if (icon != null && !mIconCache.isDefaultIcon(icon, myUserHandle)) { byte[] blob = packIcon(dpi, icon); writeRowToBackup(key, blob, out, data); } @@ -556,6 +564,7 @@ public class LauncherBackupHelper implements BackupHelper { } return; } else { + if (VERBOSE) Log.v(TAG, "saving restored icon as: " + key.name); IconCache.preloadIcon(mContext, ComponentName.unflattenFromString(key.name), icon, res.dpi); } @@ -595,7 +604,8 @@ public class LauncherBackupHelper implements BackupHelper { int startRows = out.rows; if (DEBUG) Log.d(TAG, "starting here: " + startRows); - String where = Favorites.ITEM_TYPE + "=" + Favorites.ITEM_TYPE_APPWIDGET; + String where = Favorites.ITEM_TYPE + "=" + Favorites.ITEM_TYPE_APPWIDGET + " AND " + + getUserSelectionArg(); Cursor cursor = cr.query(Favorites.CONTENT_URI, FAVORITE_PROJECTION, where, null, null); Set<String> currentIds = new HashSet<String>(cursor.getCount()); @@ -670,6 +680,9 @@ public class LauncherBackupHelper implements BackupHelper { .decodeByteArray(widget.icon.data, 0, widget.icon.data.length); if (icon == null) { Log.w(TAG, "failed to unpack widget icon for " + key.name); + } else { + IconCache.preloadIcon(mContext, ComponentName.unflattenFromString(widget.provider), + icon, widget.icon.dpi); } } @@ -798,9 +811,15 @@ public class LauncherBackupHelper implements BackupHelper { if (!TextUtils.isEmpty(title)) { favorite.title = title; } - String intent = c.getString(INTENT_INDEX); - if (!TextUtils.isEmpty(intent)) { - favorite.intent = intent; + String intentDescription = c.getString(INTENT_INDEX); + if (!TextUtils.isEmpty(intentDescription)) { + try { + Intent intent = Intent.parseUri(intentDescription, 0); + intent.removeExtra(ItemInfo.EXTRA_PROFILE); + favorite.intent = intent.toUri(0); + } catch (URISyntaxException e) { + Log.e(TAG, "Invalid intent", e); + } } favorite.itemType = c.getInt(ITEM_TYPE_INDEX); if (favorite.itemType == Favorites.ITEM_TYPE_APPWIDGET) { @@ -846,16 +865,26 @@ public class LauncherBackupHelper implements BackupHelper { values.put(Favorites.INTENT, favorite.intent); } values.put(Favorites.ITEM_TYPE, favorite.itemType); + + UserHandleCompat myUserHandle = UserHandleCompat.myUserHandle(); + long userSerialNumber = + UserManagerCompat.getInstance(mContext).getSerialNumberForUser(myUserHandle); + values.put(LauncherSettings.Favorites.PROFILE_ID, userSerialNumber); + if (favorite.itemType == Favorites.ITEM_TYPE_APPWIDGET) { if (!TextUtils.isEmpty(favorite.appWidgetProvider)) { values.put(Favorites.APPWIDGET_PROVIDER, favorite.appWidgetProvider); } values.put(Favorites.APPWIDGET_ID, favorite.appWidgetId); + values.put(LauncherSettings.Favorites.RESTORED, + LauncherAppWidgetInfo.FLAG_ID_NOT_VALID | + LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY | + LauncherAppWidgetInfo.FLAG_UI_NOT_READY); + } else { + // Let LauncherModel know we've been here. + values.put(LauncherSettings.Favorites.RESTORED, 1); } - // Let LauncherModel know we've been here. - values.put(LauncherSettings.Favorites.RESTORED, 1); - return values; } @@ -1151,6 +1180,11 @@ public class LauncherBackupHelper implements BackupHelper { return true; } + private String getUserSelectionArg() { + return Favorites.PROFILE_ID + '=' + UserManagerCompat.getInstance(mContext) + .getSerialNumberForUser(UserHandleCompat.myUserHandle()); + } + private class KeyParsingException extends Throwable { private KeyParsingException(Throwable cause) { super(cause); diff --git a/src/com/android/launcher3/LauncherClings.java b/src/com/android/launcher3/LauncherClings.java index 952edfd06..458d81f61 100644 --- a/src/com/android/launcher3/LauncherClings.java +++ b/src/com/android/launcher3/LauncherClings.java @@ -18,324 +18,186 @@ package com.android.launcher3; import android.accounts.Account; import android.accounts.AccountManager; -import android.animation.Animator; -import android.animation.AnimatorListenerAdapter; +import android.animation.ObjectAnimator; +import android.animation.PropertyValuesHolder; import android.app.ActivityManager; import android.content.Context; import android.content.SharedPreferences; -import android.graphics.Rect; +import android.graphics.drawable.Drawable; import android.os.Bundle; import android.os.UserManager; +import android.provider.Settings; +import android.view.ContextThemeWrapper; import android.view.LayoutInflater; import android.view.View; +import android.view.View.OnClickListener; +import android.view.View.OnLongClickListener; import android.view.ViewGroup; +import android.view.ViewTreeObserver.OnGlobalLayoutListener; import android.view.accessibility.AccessibilityManager; -import android.widget.TextView; -class LauncherClings { - private static final String FIRST_RUN_CLING_DISMISSED_KEY = "cling_gel.first_run.dismissed"; +class LauncherClings implements OnClickListener { private static final String MIGRATION_CLING_DISMISSED_KEY = "cling_gel.migration.dismissed"; - private static final String MIGRATION_WORKSPACE_CLING_DISMISSED_KEY = - "cling_gel.migration_workspace.dismissed"; private static final String WORKSPACE_CLING_DISMISSED_KEY = "cling_gel.workspace.dismissed"; - private static final String FOLDER_CLING_DISMISSED_KEY = "cling_gel.folder.dismissed"; + + private static final String TAG_CROP_TOP_AND_SIDES = "crop_bg_top_and_sides"; private static final boolean DISABLE_CLINGS = false; private static final int SHOW_CLING_DURATION = 250; private static final int DISMISS_CLING_DURATION = 200; + // New Secure Setting in L + private static final String SKIP_FIRST_USE_HINTS = "skip_first_use_hints"; + private Launcher mLauncher; private LayoutInflater mInflater; - private HideFromAccessibilityHelper mHideFromAccessibilityHelper - = new HideFromAccessibilityHelper(); /** Ctor */ public LauncherClings(Launcher launcher) { mLauncher = launcher; - mInflater = mLauncher.getLayoutInflater(); + mInflater = LayoutInflater.from(new + ContextThemeWrapper(mLauncher, android.R.style.Theme_DeviceDefault)); } - /** Initializes a cling */ - private Cling initCling(int clingId, int scrimId, boolean animate, - boolean dimNavBarVisibilty) { - Cling cling = (Cling) mLauncher.findViewById(clingId); - View scrim = null; - if (scrimId > 0) { - scrim = mLauncher.findViewById(scrimId); - } - if (cling != null) { - cling.init(mLauncher, scrim); - cling.show(animate, SHOW_CLING_DURATION); - - if (dimNavBarVisibilty) { - cling.setSystemUiVisibility(cling.getSystemUiVisibility() | - View.SYSTEM_UI_FLAG_LOW_PROFILE); - } + @Override + public void onClick(View v) { + int id = v.getId(); + if (id == R.id.cling_dismiss_migration_use_default) { + // Disable the migration cling + dismissMigrationCling(); + } else if (id == R.id.cling_dismiss_migration_copy_apps) { + // Copy the shortcuts from the old database + LauncherModel model = mLauncher.getModel(); + model.resetLoadedState(false, true); + model.startLoader(false, PagedView.INVALID_RESTORE_PAGE, + LauncherModel.LOADER_FLAG_CLEAR_WORKSPACE + | LauncherModel.LOADER_FLAG_MIGRATE_SHORTCUTS); + // Set the flag to skip the folder cling + String spKey = LauncherAppState.getSharedPreferencesKey(); + SharedPreferences sp = mLauncher.getSharedPreferences(spKey, Context.MODE_PRIVATE); + SharedPreferences.Editor editor = sp.edit(); + editor.putBoolean(Launcher.USER_HAS_MIGRATED, true); + editor.apply(); + // Disable the migration cling + dismissMigrationCling(); + } else if (id == R.id.cling_dismiss_longpress_info) { + dismissLongPressCling(); } - return cling; } - /** Returns whether the clings are enabled or should be shown */ - private boolean areClingsEnabled() { - if (DISABLE_CLINGS) { - return false; - } - - // disable clings when running in a test harness - if(ActivityManager.isRunningInTestHarness()) return false; + /** + * Shows the migration cling. + * + * This flow is mutually exclusive with showFirstRunCling, and only runs if this Launcher + * package was not preinstalled and there exists a db to migrate from. + */ + public void showMigrationCling() { + mLauncher.hideWorkspaceSearchAndHotseat(); - // Disable clings for accessibility when explore by touch is enabled - final AccessibilityManager a11yManager = (AccessibilityManager) mLauncher.getSystemService( - Launcher.ACCESSIBILITY_SERVICE); - if (a11yManager.isTouchExplorationEnabled()) { - return false; - } + ViewGroup root = (ViewGroup) mLauncher.findViewById(R.id.launcher); + View inflated = mInflater.inflate(R.layout.migration_cling, root); + inflated.findViewById(R.id.cling_dismiss_migration_copy_apps).setOnClickListener(this); + inflated.findViewById(R.id.cling_dismiss_migration_use_default).setOnClickListener(this); + } - // Restricted secondary users (child mode) will potentially have very few apps - // seeded when they start up for the first time. Clings won't work well with that - boolean supportsLimitedUsers = - android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR2; - Account[] accounts = AccountManager.get(mLauncher).getAccounts(); - if (supportsLimitedUsers && accounts.length == 0) { - UserManager um = (UserManager) mLauncher.getSystemService(Context.USER_SERVICE); - Bundle restrictions = um.getUserRestrictions(); - if (restrictions.getBoolean(UserManager.DISALLOW_MODIFY_ACCOUNTS, false)) { - return false; + private void dismissMigrationCling() { + mLauncher.showWorkspaceSearchAndHotseat(); + Runnable dismissCb = new Runnable() { + public void run() { + Runnable cb = new Runnable() { + public void run() { + // Show the longpress cling next + showLongPressCling(false); + } + }; + dismissCling(mLauncher.findViewById(R.id.migration_cling), cb, + MIGRATION_CLING_DISMISSED_KEY, DISMISS_CLING_DURATION); } - } - return true; + }; + mLauncher.getWorkspace().post(dismissCb); } - /** Returns whether the folder cling is visible. */ - public boolean isFolderClingVisible() { - Cling cling = (Cling) mLauncher.findViewById(R.id.folder_cling); - if (cling != null) { - return cling.getVisibility() == View.VISIBLE; - } - return false; - } + public void showLongPressCling(boolean showWelcome) { + ViewGroup root = (ViewGroup) mLauncher.findViewById(R.id.launcher); + View cling = mInflater.inflate(R.layout.longpress_cling, root, false); - private boolean skipCustomClingIfNoAccounts() { - Cling cling = (Cling) mLauncher.findViewById(R.id.workspace_cling); - boolean customCling = cling.getDrawIdentifier().equals("workspace_custom"); - if (customCling) { - AccountManager am = AccountManager.get(mLauncher); - if (am == null) return false; - Account[] accounts = am.getAccountsByType("com.google"); - return accounts.length == 0; - } - return false; - } + cling.setOnLongClickListener(new OnLongClickListener() { - /** Updates the first run cling custom content hint */ - private void setCustomContentHintVisibility(Cling cling, String ccHintStr, boolean visible, - boolean animate) { - final TextView ccHint = (TextView) cling.findViewById(R.id.custom_content_hint); - if (ccHint != null) { - if (visible && !ccHintStr.isEmpty()) { - ccHint.setText(ccHintStr); - ccHint.setVisibility(View.VISIBLE); - if (animate) { - ccHint.setAlpha(0f); - ccHint.animate().alpha(1f) - .setDuration(SHOW_CLING_DURATION) - .start(); - } else { - ccHint.setAlpha(1f); - } - } else { - if (animate) { - ccHint.animate().alpha(0f) - .setDuration(SHOW_CLING_DURATION) - .setListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - ccHint.setVisibility(View.GONE); - } - }) - .start(); - } else { - ccHint.setAlpha(0f); - ccHint.setVisibility(View.GONE); - } + @Override + public boolean onLongClick(View v) { + mLauncher.getWorkspace().enterOverviewMode(); + dismissLongPressCling(); + return true; } - } - } + }); - /** Updates the first run cling custom content hint */ - public void updateCustomContentHintVisibility() { - Cling cling = (Cling) mLauncher.findViewById(R.id.first_run_cling); - String ccHintStr = mLauncher.getFirstRunCustomContentHint(); + final ViewGroup content = (ViewGroup) cling.findViewById(R.id.cling_content); + mInflater.inflate(showWelcome ? R.layout.longpress_cling_welcome_content + : R.layout.longpress_cling_content, content); + content.findViewById(R.id.cling_dismiss_longpress_info).setOnClickListener(this); - if (mLauncher.getWorkspace().hasCustomContent()) { - // Show the custom content hint if ccHintStr is not empty - if (cling != null) { - setCustomContentHintVisibility(cling, ccHintStr, true, true); - } - } else { - // Hide the custom content hint - if (cling != null) { - setCustomContentHintVisibility(cling, ccHintStr, false, true); - } + if (TAG_CROP_TOP_AND_SIDES.equals(content.getTag())) { + Drawable bg = new BorderCropDrawable(mLauncher.getResources().getDrawable(R.drawable.cling_bg), + true, true, true, false); + content.setBackground(bg); } - } - /** Updates the first run cling search bar hint. */ - public void updateSearchBarHint(String hint) { - Cling cling = (Cling) mLauncher.findViewById(R.id.first_run_cling); - if (cling != null && cling.getVisibility() == View.VISIBLE && !hint.isEmpty()) { - TextView sbHint = (TextView) cling.findViewById(R.id.search_bar_hint); - sbHint.setText(hint); - sbHint.setVisibility(View.VISIBLE); - } - } + root.addView(cling); - public boolean shouldShowFirstRunOrMigrationClings() { - SharedPreferences sharedPrefs = mLauncher.getSharedPrefs(); - return areClingsEnabled() && - !sharedPrefs.getBoolean(FIRST_RUN_CLING_DISMISSED_KEY, false) && - !sharedPrefs.getBoolean(MIGRATION_CLING_DISMISSED_KEY, false); - } - - public void removeFirstRunAndMigrationClings() { - removeCling(R.id.first_run_cling); - removeCling(R.id.migration_cling); - } - - /** - * Shows the first run cling. - * - * This flow is mutually exclusive with showMigrationCling, and only runs if this Launcher - * package was preinstalled or there is no db to migrate from. - */ - public void showFirstRunCling() { - if (!skipCustomClingIfNoAccounts()) { - Cling cling = (Cling) mLauncher.findViewById(R.id.first_run_cling); - if (cling != null) { - String sbHintStr = mLauncher.getFirstRunClingSearchBarHint(); - String ccHintStr = mLauncher.getFirstRunCustomContentHint(); - if (!sbHintStr.isEmpty()) { - TextView sbHint = (TextView) cling.findViewById(R.id.search_bar_hint); - sbHint.setText(sbHintStr); - sbHint.setVisibility(View.VISIBLE); - } - setCustomContentHintVisibility(cling, ccHintStr, true, false); - } - initCling(R.id.first_run_cling, 0, false, true); - } else { - removeFirstRunAndMigrationClings(); + if (showWelcome) { + // This is the first cling being shown. No need to animate. + return; } - } - /** - * Shows the migration cling. - * - * This flow is mutually exclusive with showFirstRunCling, and only runs if this Launcher - * package was not preinstalled and there exists a db to migrate from. - */ - public void showMigrationCling() { - mLauncher.hideWorkspaceSearchAndHotseat(); - - Cling c = initCling(R.id.migration_cling, 0, false, true); - c.bringScrimToFront(); - c.bringToFront(); - } + // Animate + content.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() { - public void showMigrationWorkspaceCling() { - // Enable the clings only if they have not been dismissed before - if (areClingsEnabled() && !mLauncher.getSharedPrefs().getBoolean( - MIGRATION_WORKSPACE_CLING_DISMISSED_KEY, false)) { - Cling c = initCling(R.id.migration_workspace_cling, 0, false, true); - c.updateMigrationWorkspaceBubblePosition(); - c.bringScrimToFront(); - c.bringToFront(); - } else { - removeCling(R.id.migration_workspace_cling); - } - } + @Override + public void onGlobalLayout() { + content.getViewTreeObserver().removeOnGlobalLayoutListener(this); - public void showWorkspaceCling() { - // Enable the clings only if they have not been dismissed before - if (areClingsEnabled() && !mLauncher.getSharedPrefs().getBoolean( - WORKSPACE_CLING_DISMISSED_KEY, false)) { - Cling c = initCling(R.id.workspace_cling, 0, false, true); - c.updateWorkspaceBubblePosition(); - - // Set the focused hotseat app if there is one - c.setFocusedHotseatApp(mLauncher.getFirstRunFocusedHotseatAppDrawableId(), - mLauncher.getFirstRunFocusedHotseatAppRank(), - mLauncher.getFirstRunFocusedHotseatAppComponentName(), - mLauncher.getFirstRunFocusedHotseatAppBubbleTitle(), - mLauncher.getFirstRunFocusedHotseatAppBubbleDescription()); - } else { - removeCling(R.id.workspace_cling); - } - } + ObjectAnimator anim; + if (TAG_CROP_TOP_AND_SIDES.equals(content.getTag())) { + content.setTranslationY(-content.getMeasuredHeight()); + anim = LauncherAnimUtils.ofFloat(content, "translationY", 0); + } else { + content.setScaleX(0); + content.setScaleY(0); + PropertyValuesHolder scaleX = PropertyValuesHolder.ofFloat("scaleX", 1); + PropertyValuesHolder scaleY = PropertyValuesHolder.ofFloat("scaleY", 1); + anim = LauncherAnimUtils.ofPropertyValuesHolder(content, scaleX, scaleY); + } - public Cling showFoldersCling() { - SharedPreferences sharedPrefs = mLauncher.getSharedPrefs(); - // Enable the clings only if they have not been dismissed before - if (areClingsEnabled() && - !sharedPrefs.getBoolean(FOLDER_CLING_DISMISSED_KEY, false) && - !sharedPrefs.getBoolean(Launcher.USER_HAS_MIGRATED, false)) { - Cling cling = initCling(R.id.folder_cling, R.id.cling_scrim, - true, true); - Folder openFolder = mLauncher.getWorkspace().getOpenFolder(); - if (openFolder != null) { - Rect openFolderRect = new Rect(); - openFolder.getHitRect(openFolderRect); - cling.setOpenFolderRect(openFolderRect); - openFolder.bringToFront(); + anim.setDuration(SHOW_CLING_DURATION); + anim.setInterpolator(new LogDecelerateInterpolator(100, 0)); + anim.start(); } - return cling; - } else { - removeCling(R.id.folder_cling); - return null; - } + }); } - public static void synchonouslyMarkFirstRunClingDismissed(Context ctx) { - SharedPreferences prefs = ctx.getSharedPreferences( - LauncherAppState.getSharedPreferencesKey(), Context.MODE_PRIVATE); - SharedPreferences.Editor editor = prefs.edit(); - editor.putBoolean(LauncherClings.FIRST_RUN_CLING_DISMISSED_KEY, true); - editor.commit(); - } - - public void markFolderClingDismissed() { - SharedPreferences.Editor editor = mLauncher.getSharedPrefs().edit(); - editor.putBoolean(LauncherClings.FOLDER_CLING_DISMISSED_KEY, true); - editor.apply(); - } - - /** Removes the cling outright from the DragLayer */ - private void removeCling(int id) { - final View cling = mLauncher.findViewById(id); - if (cling != null) { - final ViewGroup parent = (ViewGroup) cling.getParent(); - parent.post(new Runnable() { - @Override - public void run() { - parent.removeView(cling); - } - }); - mHideFromAccessibilityHelper.restoreImportantForAccessibility(mLauncher.getDragLayer()); - } + private void dismissLongPressCling() { + Runnable dismissCb = new Runnable() { + public void run() { + dismissCling(mLauncher.findViewById(R.id.longpress_cling), null, + WORKSPACE_CLING_DISMISSED_KEY, DISMISS_CLING_DURATION); + } + }; + mLauncher.getWorkspace().post(dismissCb); } /** Hides the specified Cling */ - private void dismissCling(final Cling cling, final Runnable postAnimationCb, - final String flag, int duration, boolean restoreNavBarVisibilty) { + private void dismissCling(final View cling, final Runnable postAnimationCb, + final String flag, int duration) { // To catch cases where siblings of top-level views are made invisible, just check whether // the cling is directly set to GONE before dismissing it. if (cling != null && cling.getVisibility() != View.GONE) { final Runnable cleanUpClingCb = new Runnable() { public void run() { - cling.cleanup(); - SharedPreferences.Editor editor = mLauncher.getSharedPrefs().edit(); - editor.putBoolean(flag, true); - editor.apply(); + cling.setVisibility(View.GONE); + mLauncher.getSharedPrefs().edit() + .putBoolean(flag, true) + .apply(); if (postAnimationCb != null) { postAnimationCb.run(); } @@ -344,108 +206,58 @@ class LauncherClings { if (duration <= 0) { cleanUpClingCb.run(); } else { - cling.hide(duration, cleanUpClingCb); - } - mHideFromAccessibilityHelper.restoreImportantForAccessibility(mLauncher.getDragLayer()); - - if (restoreNavBarVisibilty) { - cling.setSystemUiVisibility(cling.getSystemUiVisibility() & - ~View.SYSTEM_UI_FLAG_LOW_PROFILE); + cling.animate().alpha(0).setDuration(duration).withEndAction(cleanUpClingCb); } } } - public void dismissFirstRunCling(View v) { - Cling cling = (Cling) mLauncher.findViewById(R.id.first_run_cling); - Runnable cb = new Runnable() { - public void run() { - // Show the workspace cling next - showWorkspaceCling(); - } - }; - dismissCling(cling, cb, FIRST_RUN_CLING_DISMISSED_KEY, - DISMISS_CLING_DURATION, false); - - // Fade out the search bar for the workspace cling coming up - mLauncher.getSearchBar().hideSearchBar(true); - } - - private void dismissMigrationCling() { - mLauncher.showWorkspaceSearchAndHotseat(); - Runnable dismissCb = new Runnable() { - public void run() { - Cling cling = (Cling) mLauncher.findViewById(R.id.migration_cling); - Runnable cb = new Runnable() { - public void run() { - // Show the migration workspace cling next - showMigrationWorkspaceCling(); - } - }; - dismissCling(cling, cb, MIGRATION_CLING_DISMISSED_KEY, - DISMISS_CLING_DURATION, true); - } - }; - mLauncher.getWorkspace().post(dismissCb); - } - - private void dismissAnyWorkspaceCling(Cling cling, String key, View v) { - Runnable cb = null; - if (v == null) { - cb = new Runnable() { - public void run() { - mLauncher.getWorkspace().enterOverviewMode(); - } - }; + /** Returns whether the clings are enabled or should be shown */ + private boolean areClingsEnabled() { + if (DISABLE_CLINGS) { + return false; } - dismissCling(cling, cb, key, DISMISS_CLING_DURATION, true); - - // Fade in the search bar - mLauncher.getSearchBar().showSearchBar(true); - } - - public void dismissMigrationClingCopyApps(View v) { - // Copy the shortcuts from the old database - LauncherModel model = mLauncher.getModel(); - model.resetLoadedState(false, true); - model.startLoader(false, PagedView.INVALID_RESTORE_PAGE, - LauncherModel.LOADER_FLAG_CLEAR_WORKSPACE - | LauncherModel.LOADER_FLAG_MIGRATE_SHORTCUTS); - - // Set the flag to skip the folder cling - String spKey = LauncherAppState.getSharedPreferencesKey(); - SharedPreferences sp = mLauncher.getSharedPreferences(spKey, Context.MODE_PRIVATE); - SharedPreferences.Editor editor = sp.edit(); - editor.putBoolean(Launcher.USER_HAS_MIGRATED, true); - editor.apply(); - - // Disable the migration cling - dismissMigrationCling(); - } - public void dismissMigrationClingUseDefault(View v) { - // Clear the workspace - LauncherModel model = mLauncher.getModel(); - model.resetLoadedState(false, true); - model.startLoader(false, PagedView.INVALID_RESTORE_PAGE, - LauncherModel.LOADER_FLAG_CLEAR_WORKSPACE); + // disable clings when running in a test harness + if(ActivityManager.isRunningInTestHarness()) return false; - // Disable the migration cling - dismissMigrationCling(); - } + // Disable clings for accessibility when explore by touch is enabled + final AccessibilityManager a11yManager = (AccessibilityManager) mLauncher.getSystemService( + Launcher.ACCESSIBILITY_SERVICE); + if (a11yManager.isTouchExplorationEnabled()) { + return false; + } - public void dismissMigrationWorkspaceCling(View v) { - Cling cling = (Cling) mLauncher.findViewById(R.id.migration_workspace_cling); - dismissAnyWorkspaceCling(cling, MIGRATION_WORKSPACE_CLING_DISMISSED_KEY, v); + // Restricted secondary users (child mode) will potentially have very few apps + // seeded when they start up for the first time. Clings won't work well with that + boolean supportsLimitedUsers = + android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR2; + Account[] accounts = AccountManager.get(mLauncher).getAccounts(); + if (supportsLimitedUsers && accounts.length == 0) { + UserManager um = (UserManager) mLauncher.getSystemService(Context.USER_SERVICE); + Bundle restrictions = um.getUserRestrictions(); + if (restrictions.getBoolean(UserManager.DISALLOW_MODIFY_ACCOUNTS, false)) { + return false; + } + } + if (Settings.Secure.getInt(mLauncher.getContentResolver(), SKIP_FIRST_USE_HINTS, 0) + == 1) { + return false; + } + return true; } - public void dismissWorkspaceCling(View v) { - Cling cling = (Cling) mLauncher.findViewById(R.id.workspace_cling); - dismissAnyWorkspaceCling(cling, WORKSPACE_CLING_DISMISSED_KEY, v); + public boolean shouldShowFirstRunOrMigrationClings() { + SharedPreferences sharedPrefs = mLauncher.getSharedPrefs(); + return areClingsEnabled() && + !sharedPrefs.getBoolean(WORKSPACE_CLING_DISMISSED_KEY, false) && + !sharedPrefs.getBoolean(MIGRATION_CLING_DISMISSED_KEY, false); } - public void dismissFolderCling(View v) { - Cling cling = (Cling) mLauncher.findViewById(R.id.folder_cling); - dismissCling(cling, null, FOLDER_CLING_DISMISSED_KEY, - DISMISS_CLING_DURATION, true); + public static void synchonouslyMarkFirstRunClingDismissed(Context ctx) { + SharedPreferences prefs = ctx.getSharedPreferences( + LauncherAppState.getSharedPreferencesKey(), Context.MODE_PRIVATE); + SharedPreferences.Editor editor = prefs.edit(); + editor.putBoolean(WORKSPACE_CLING_DISMISSED_KEY, true); + editor.commit(); } } diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java index 007fd7a4a..c64506d80 100644 --- a/src/com/android/launcher3/LauncherModel.java +++ b/src/com/android/launcher3/LauncherModel.java @@ -19,12 +19,19 @@ package com.android.launcher3; import android.app.SearchManager; import android.appwidget.AppWidgetManager; import android.appwidget.AppWidgetProviderInfo; -import android.content.*; +import android.content.BroadcastReceiver; +import android.content.ComponentName; +import android.content.ContentProviderClient; +import android.content.ContentProviderOperation; +import android.content.ContentResolver; +import android.content.ContentValues; +import android.content.Context; +import android.content.Intent; import android.content.Intent.ShortcutIconResource; -import android.content.pm.ActivityInfo; -import android.content.pm.PackageInfo; +import android.content.IntentFilter; +import android.content.SharedPreferences; import android.content.pm.PackageManager; -import android.content.pm.PackageManager.NameNotFoundException; +import android.content.pm.ProviderInfo; import android.content.pm.ResolveInfo; import android.content.res.Configuration; import android.content.res.Resources; @@ -44,10 +51,17 @@ import android.text.TextUtils; import android.util.Log; import android.util.Pair; -import com.android.launcher3.InstallWidgetReceiver.WidgetMimeTypeHandlerData; +import com.android.launcher3.compat.AppWidgetManagerCompat; +import com.android.launcher3.compat.LauncherActivityInfoCompat; +import com.android.launcher3.compat.LauncherAppsCompat; +import com.android.launcher3.compat.PackageInstallerCompat; +import com.android.launcher3.compat.PackageInstallerCompat.PackageInstallInfo; +import com.android.launcher3.compat.UserHandleCompat; +import com.android.launcher3.compat.UserManagerCompat; import java.lang.ref.WeakReference; import java.net.URISyntaxException; +import java.security.InvalidParameterException; import java.text.Collator; import java.util.ArrayList; import java.util.Arrays; @@ -58,6 +72,7 @@ import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; +import java.util.Map.Entry; import java.util.Set; import java.util.TreeMap; import java.util.concurrent.atomic.AtomicBoolean; @@ -67,14 +82,17 @@ import java.util.concurrent.atomic.AtomicBoolean; * LauncherModel object held in a static. Also provide APIs for updating the database state * for the Launcher. */ -public class LauncherModel extends BroadcastReceiver { +public class LauncherModel extends BroadcastReceiver + implements LauncherAppsCompat.OnAppsChangedCallbackCompat { static final boolean DEBUG_LOADERS = false; + private static final boolean DEBUG_RECEIVER = false; + private static final boolean REMOVE_UNRESTORED_ICONS = true; + static final String TAG = "Launcher.Model"; // true = use a "More Apps" folder for non-workspace apps on upgrade // false = strew non-workspace apps across the workspace on upgrade public static final boolean UPGRADE_USE_MORE_APPS_FOLDER = false; - public static final int LOADER_FLAG_NONE = 0; public static final int LOADER_FLAG_CLEAR_WORKSPACE = 1 << 0; public static final int LOADER_FLAG_MIGRATE_SHORTCUTS = 1 << 1; @@ -97,6 +115,7 @@ public class LauncherModel extends BroadcastReceiver { private static final int MAIN_THREAD_NORMAL_RUNNABLE = 0; private static final int MAIN_THREAD_BINDING_RUNNABLE = 1; + private static final String MIGRATE_AUTHORITY = "com.android.launcher2.settings"; private static final HandlerThread sWorkerThread = new HandlerThread("launcher-loader"); static { @@ -149,13 +168,19 @@ public class LauncherModel extends BroadcastReceiver { // sBgWorkspaceScreens is the ordered set of workspace screens. static final ArrayList<Long> sBgWorkspaceScreens = new ArrayList<Long>(); + // sPendingPackages is a set of packages which could be on sdcard and are not available yet + static final HashMap<UserHandleCompat, HashSet<String>> sPendingPackages = + new HashMap<UserHandleCompat, HashSet<String>>(); + // </ only access in worker thread > private IconCache mIconCache; - private Bitmap mDefaultIcon; protected int mPreviousConfigMcc; + private final LauncherAppsCompat mLauncherApps; + private final UserManagerCompat mUserManager; + public interface Callbacks { public boolean setLoadOnResume(); public int getCurrentWorkspaceScreen(); @@ -173,8 +198,11 @@ public class LauncherModel extends BroadcastReceiver { ArrayList<ItemInfo> addAnimated, ArrayList<AppInfo> addedApps); public void bindAppsUpdated(ArrayList<AppInfo> apps); + public void bindAppsRestored(ArrayList<AppInfo> apps); + public void updatePackageState(ArrayList<PackageInstallInfo> installInfo); + public void updatePackageBadge(String packageName); public void bindComponentsRemoved(ArrayList<String> packageNames, - ArrayList<AppInfo> appInfos); + ArrayList<AppInfo> appInfos, UserHandleCompat user); public void bindPackagesUpdated(ArrayList<Object> widgetsAndShortcuts); public void bindSearchablesChanged(); public boolean isAllAppsButtonRank(int rank); @@ -188,11 +216,26 @@ public class LauncherModel extends BroadcastReceiver { LauncherModel(LauncherAppState app, IconCache iconCache, AppFilter appFilter) { Context context = app.getContext(); - ContentResolver contentResolver = context.getContentResolver(); mAppsCanBeOnRemoveableStorage = Environment.isExternalStorageRemovable(); - mOldContentProviderExists = (contentResolver.acquireContentProviderClient( - LauncherSettings.Favorites.OLD_CONTENT_URI) != null); + String oldProvider = context.getString(R.string.old_launcher_provider_uri); + // This may be the same as MIGRATE_AUTHORITY, or it may be replaced by a different + // resource string. + String redirectAuthority = Uri.parse(oldProvider).getAuthority(); + ProviderInfo providerInfo = + context.getPackageManager().resolveContentProvider(MIGRATE_AUTHORITY, 0); + ProviderInfo redirectProvider = + context.getPackageManager().resolveContentProvider(redirectAuthority, 0); + + Log.d(TAG, "Old launcher provider: " + oldProvider); + mOldContentProviderExists = (providerInfo != null) && (redirectProvider != null); + + if (mOldContentProviderExists) { + Log.d(TAG, "Old launcher provider exists."); + } else { + Log.d(TAG, "Old launcher provider does not exist."); + } + mApp = app; mBgAllAppsList = new AllAppsList(iconCache, appFilter); mIconCache = iconCache; @@ -200,6 +243,8 @@ public class LauncherModel extends BroadcastReceiver { final Resources res = context.getResources(); Configuration config = res.getConfiguration(); mPreviousConfigMcc = config.mcc; + mLauncherApps = LauncherAppsCompat.getInstance(context); + mUserManager = UserManagerCompat.getInstance(context); } /** Runs the specified runnable immediately if called from the main thread, otherwise it is @@ -292,6 +337,32 @@ public class LauncherModel extends BroadcastReceiver { return null; } + public void setPackageState(final ArrayList<PackageInstallInfo> installInfo) { + // Process the updated package state + Runnable r = new Runnable() { + public void run() { + Callbacks callbacks = mCallbacks != null ? mCallbacks.get() : null; + if (callbacks != null) { + callbacks.updatePackageState(installInfo); + } + } + }; + mHandler.post(r); + } + + public void updatePackageBadge(final String packageName) { + // Process the updated package badge + Runnable r = new Runnable() { + public void run() { + Callbacks callbacks = mCallbacks != null ? mCallbacks.get() : null; + if (callbacks != null) { + callbacks.updatePackageBadge(packageName); + } + } + }; + mHandler.post(r); + } + public void addAppsToAllApps(final Context ctx, final ArrayList<AppInfo> allAppsApps) { final Callbacks callbacks = mCallbacks != null ? mCallbacks.get() : null; @@ -306,7 +377,7 @@ public class LauncherModel extends BroadcastReceiver { Iterator<AppInfo> iter = allAppsApps.iterator(); while (iter.hasNext()) { ItemInfo a = iter.next(); - if (LauncherModel.appWasRestored(ctx, a.getIntent())) { + if (LauncherModel.appWasPromise(ctx, a.getIntent(), a.user)) { restoredAppsFinal.add((AppInfo) a); } } @@ -322,7 +393,8 @@ public class LauncherModel extends BroadcastReceiver { for (AppInfo info : restoredAppsFinal) { final Intent intent = info.getIntent(); if (intent != null) { - mIconCache.deletePreloadedIcon(intent.getComponent()); + mIconCache.deletePreloadedIcon(intent.getComponent(), + info.user); } } callbacks.bindAppsUpdated(restoredAppsFinal); @@ -374,7 +446,7 @@ public class LauncherModel extends BroadcastReceiver { if (LauncherModel.shortcutExists(context, name, launchIntent)) { // Only InstallShortcutReceiver sends us shortcutInfos, ignore them if (a instanceof AppInfo && - LauncherModel.appWasRestored(context, launchIntent)) { + LauncherModel.appWasPromise(context, launchIntent, a.user)) { restoredAppsFinal.add((AppInfo) a); } continue; @@ -464,15 +536,6 @@ public class LauncherModel extends BroadcastReceiver { runOnWorkerThread(r); } - public Bitmap getFallbackIcon() { - if (mDefaultIcon == null) { - final Context context = LauncherAppState.getInstance().getContext(); - mDefaultIcon = Utilities.createIconBitmap( - mIconCache.getFullResDefaultActivityIcon(), context); - } - return Bitmap.createBitmap(mDefaultIcon); - } - public void unbindItemInfosAndClearQueuedBindRunnables() { if (sWorkerThread.getThreadId() == Process.myTid()) { throw new RuntimeException("Expected unbindLauncherItemInfos() to be called from the " + @@ -480,7 +543,9 @@ public class LauncherModel extends BroadcastReceiver { } // Clear any deferred bind runnables - mDeferredBindRunnables.clear(); + synchronized (mDeferredBindRunnables) { + mDeferredBindRunnables.clear(); + } // Remove any queued bind runnables mHandler.cancelAllRunnablesOfType(MAIN_THREAD_BINDING_RUNNABLE); // Unbind all the workspace items @@ -796,7 +861,7 @@ public class LauncherModel extends BroadcastReceiver { */ static void updateItemInDatabase(Context context, final ItemInfo item) { final ContentValues values = new ContentValues(); - item.onAddToDatabase(values); + item.onAddToDatabase(context, values); item.updateValuesWithCoordinates(values, item.cellX, item.cellY); updateItemInDatabaseHelper(context, values, item, "updateItemInDatabase"); } @@ -807,9 +872,26 @@ public class LauncherModel extends BroadcastReceiver { */ static boolean shortcutExists(Context context, String title, Intent intent) { final ContentResolver cr = context.getContentResolver(); + final Intent intentWithPkg, intentWithoutPkg; + + if (intent.getComponent() != null) { + // If component is not null, an intent with null package will produce + // the same result and should also be a match. + if (intent.getPackage() != null) { + intentWithPkg = intent; + intentWithoutPkg = new Intent(intent).setPackage(null); + } else { + intentWithPkg = new Intent(intent).setPackage( + intent.getComponent().getPackageName()); + intentWithoutPkg = intent; + } + } else { + intentWithPkg = intent; + intentWithoutPkg = intent; + } Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI, - new String[] { "title", "intent" }, "title=? and intent=?", - new String[] { title, intent.toUri(0) }, null); + new String[] { "title", "intent" }, "title=? and (intent=? or intent=?)", + new String[] { title, intentWithPkg.toUri(0), intentWithoutPkg.toUri(0) }, null); boolean result = false; try { result = c.moveToFirst(); @@ -820,27 +902,14 @@ public class LauncherModel extends BroadcastReceiver { } /** - * Returns true if the shortcuts already exists in the database. - * we identify a shortcut by the component name of the intent. + * Returns true if the promise shortcuts with the same package name exists on the workspace. */ - static boolean appWasRestored(Context context, Intent intent) { - final ContentResolver cr = context.getContentResolver(); + static boolean appWasPromise(Context context, Intent intent, UserHandleCompat user) { final ComponentName component = intent.getComponent(); if (component == null) { return false; } - String componentName = component.flattenToString(); - final String where = "intent glob \"*component=" + componentName + "*\" and restored = 1"; - Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI, - new String[]{"intent", "restored"}, where, null, null); - boolean result = false; - try { - result = c.moveToFirst(); - } finally { - c.close(); - } - Log.d(TAG, "shortcutWasRestored is " + result + " for " + componentName); - return result; + return !getItemsByPackageName(component.getPackageName(), user).isEmpty(); } /** @@ -852,8 +921,10 @@ public class LauncherModel extends BroadcastReceiver { final ContentResolver cr = context.getContentResolver(); Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI, new String[] { LauncherSettings.Favorites.ITEM_TYPE, LauncherSettings.Favorites.CONTAINER, - LauncherSettings.Favorites.SCREEN, LauncherSettings.Favorites.CELLX, LauncherSettings.Favorites.CELLY, - LauncherSettings.Favorites.SPANX, LauncherSettings.Favorites.SPANY }, null, null, null); + LauncherSettings.Favorites.SCREEN, + LauncherSettings.Favorites.CELLX, LauncherSettings.Favorites.CELLY, + LauncherSettings.Favorites.SPANX, LauncherSettings.Favorites.SPANY, + LauncherSettings.Favorites.PROFILE_ID }, null, null, null); final int itemTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ITEM_TYPE); final int containerIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CONTAINER); @@ -862,7 +933,8 @@ public class LauncherModel extends BroadcastReceiver { final int cellYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLY); final int spanXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SPANX); final int spanYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SPANY); - + final int profileIdIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.PROFILE_ID); + UserManagerCompat userManager = UserManagerCompat.getInstance(context); try { while (c.moveToNext()) { ItemInfo item = new ItemInfo(); @@ -873,8 +945,12 @@ public class LauncherModel extends BroadcastReceiver { item.container = c.getInt(containerIndex); item.itemType = c.getInt(itemTypeIndex); item.screenId = c.getInt(screenIndex); - - items.add(item); + long serialNumber = c.getInt(profileIdIndex); + item.user = userManager.getUserForSerialNumber(serialNumber); + // Skip if user has been deleted. + if (item.user != null) { + items.add(item); + } } } catch (Exception e) { items.clear(); @@ -947,12 +1023,13 @@ public class LauncherModel extends BroadcastReceiver { final ContentValues values = new ContentValues(); final ContentResolver cr = context.getContentResolver(); - item.onAddToDatabase(values); + item.onAddToDatabase(context, values); item.id = LauncherAppState.getLauncherProvider().generateNewItemId(); values.put(LauncherSettings.Favorites._ID, item.id); item.updateValuesWithCoordinates(values, item.cellX, item.cellY); + final StackTraceElement[] stackTrace = new Throwable().getStackTrace(); Runnable r = new Runnable() { public void run() { cr.insert(notify ? LauncherSettings.Favorites.CONTENT_URI : @@ -960,7 +1037,7 @@ public class LauncherModel extends BroadcastReceiver { // Lock on mBgLock *after* the db operation synchronized (sBgLock) { - checkItemInfoLocked(item.id, item, null); + checkItemInfoLocked(item.id, item, stackTrace); sBgItemsIdMap.put(item.id, item); switch (item.itemType) { case LauncherSettings.Favorites.ITEM_TYPE_FOLDER: @@ -999,45 +1076,77 @@ public class LauncherModel extends BroadcastReceiver { | ((int) screen & 0xFF) << 16 | (localCellX & 0xFF) << 8 | (localCellY & 0xFF); } + private static ArrayList<ItemInfo> getItemsByPackageName( + final String pn, final UserHandleCompat user) { + ItemInfoFilter filter = new ItemInfoFilter() { + @Override + public boolean filterItem(ItemInfo parent, ItemInfo info, ComponentName cn) { + return cn.getPackageName().equals(pn) && info.user.equals(user); + } + }; + return filterItemInfos(sBgItemsIdMap.values(), filter); + } + + /** + * Removes all the items from the database corresponding to the specified package. + */ + static void deletePackageFromDatabase(Context context, final String pn, + final UserHandleCompat user) { + deleteItemsFromDatabase(context, getItemsByPackageName(pn, user)); + } + /** * Removes the specified item from the database * @param context * @param item */ static void deleteItemFromDatabase(Context context, final ItemInfo item) { + ArrayList<ItemInfo> items = new ArrayList<ItemInfo>(); + items.add(item); + deleteItemsFromDatabase(context, items); + } + + /** + * Removes the specified items from the database + * @param context + * @param item + */ + static void deleteItemsFromDatabase(Context context, final ArrayList<ItemInfo> items) { final ContentResolver cr = context.getContentResolver(); - final Uri uriToDelete = LauncherSettings.Favorites.getContentUri(item.id, false); Runnable r = new Runnable() { public void run() { - cr.delete(uriToDelete, null, null); + for (ItemInfo item : items) { + final Uri uri = LauncherSettings.Favorites.getContentUri(item.id, false); + cr.delete(uri, null, null); - // Lock on mBgLock *after* the db operation - synchronized (sBgLock) { - switch (item.itemType) { - case LauncherSettings.Favorites.ITEM_TYPE_FOLDER: - sBgFolders.remove(item.id); - for (ItemInfo info: sBgItemsIdMap.values()) { - if (info.container == item.id) { - // We are deleting a folder which still contains items that - // think they are contained by that folder. - String msg = "deleting a folder (" + item + ") which still " + - "contains items (" + info + ")"; - Log.e(TAG, msg); + // Lock on mBgLock *after* the db operation + synchronized (sBgLock) { + switch (item.itemType) { + case LauncherSettings.Favorites.ITEM_TYPE_FOLDER: + sBgFolders.remove(item.id); + for (ItemInfo info: sBgItemsIdMap.values()) { + if (info.container == item.id) { + // We are deleting a folder which still contains items that + // think they are contained by that folder. + String msg = "deleting a folder (" + item + ") which still " + + "contains items (" + info + ")"; + Log.e(TAG, msg); + } } - } - sBgWorkspaceItems.remove(item); - break; - case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION: - case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT: - sBgWorkspaceItems.remove(item); - break; - case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET: - sBgAppWidgets.remove((LauncherAppWidgetInfo) item); - break; + sBgWorkspaceItems.remove(item); + break; + case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION: + case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT: + sBgWorkspaceItems.remove(item); + break; + case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET: + sBgAppWidgets.remove((LauncherAppWidgetInfo) item); + break; + } + sBgItemsIdMap.remove(item.id); + sBgDbIconCache.remove(item); } - sBgItemsIdMap.remove(item.id); - sBgDbIconCache.remove(item); } } }; @@ -1136,74 +1245,67 @@ public class LauncherModel extends BroadcastReceiver { } } - /** - * Call from the handler for ACTION_PACKAGE_ADDED, ACTION_PACKAGE_REMOVED and - * ACTION_PACKAGE_CHANGED. - */ @Override - public void onReceive(Context context, Intent intent) { - if (DEBUG_LOADERS) Log.d(TAG, "onReceive intent=" + intent); - - final String action = intent.getAction(); + public void onPackageChanged(String packageName, UserHandleCompat user) { + int op = PackageUpdatedTask.OP_UPDATE; + enqueuePackageUpdated(new PackageUpdatedTask(op, new String[] { packageName }, + user)); + } - if (Intent.ACTION_PACKAGE_CHANGED.equals(action) - || Intent.ACTION_PACKAGE_REMOVED.equals(action) - || Intent.ACTION_PACKAGE_ADDED.equals(action)) { - final String packageName = intent.getData().getSchemeSpecificPart(); - final boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false); + @Override + public void onPackageRemoved(String packageName, UserHandleCompat user) { + int op = PackageUpdatedTask.OP_REMOVE; + enqueuePackageUpdated(new PackageUpdatedTask(op, new String[] { packageName }, + user)); + } - int op = PackageUpdatedTask.OP_NONE; + @Override + public void onPackageAdded(String packageName, UserHandleCompat user) { + int op = PackageUpdatedTask.OP_ADD; + enqueuePackageUpdated(new PackageUpdatedTask(op, new String[] { packageName }, + user)); + } - if (packageName == null || packageName.length() == 0) { - // they sent us a bad intent - return; + @Override + public void onPackagesAvailable(String[] packageNames, UserHandleCompat user, + boolean replacing) { + if (!replacing) { + enqueuePackageUpdated(new PackageUpdatedTask(PackageUpdatedTask.OP_ADD, packageNames, + user)); + if (mAppsCanBeOnRemoveableStorage) { + // Only rebind if we support removable storage. It catches the + // case where + // apps on the external sd card need to be reloaded + startLoaderFromBackground(); } + } else { + // If we are replacing then just update the packages in the list + enqueuePackageUpdated(new PackageUpdatedTask(PackageUpdatedTask.OP_UPDATE, + packageNames, user)); + } + } - if (Intent.ACTION_PACKAGE_CHANGED.equals(action)) { - op = PackageUpdatedTask.OP_UPDATE; - } else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) { - if (!replacing) { - op = PackageUpdatedTask.OP_REMOVE; - } - // else, we are replacing the package, so a PACKAGE_ADDED will be sent - // later, we will update the package at this time - } else if (Intent.ACTION_PACKAGE_ADDED.equals(action)) { - if (!replacing) { - op = PackageUpdatedTask.OP_ADD; - } else { - op = PackageUpdatedTask.OP_UPDATE; - } - } + @Override + public void onPackagesUnavailable(String[] packageNames, UserHandleCompat user, + boolean replacing) { + if (!replacing) { + enqueuePackageUpdated(new PackageUpdatedTask( + PackageUpdatedTask.OP_UNAVAILABLE, packageNames, + user)); + } - if (op != PackageUpdatedTask.OP_NONE) { - enqueuePackageUpdated(new PackageUpdatedTask(op, new String[] { packageName })); - } + } - } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)) { - final boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false); - String[] packages = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); - if (!replacing) { - enqueuePackageUpdated(new PackageUpdatedTask(PackageUpdatedTask.OP_ADD, packages)); - if (mAppsCanBeOnRemoveableStorage) { - // Only rebind if we support removable storage. It catches the case where - // apps on the external sd card need to be reloaded - startLoaderFromBackground(); - } - } else { - // If we are replacing then just update the packages in the list - enqueuePackageUpdated(new PackageUpdatedTask(PackageUpdatedTask.OP_UPDATE, - packages)); - } - } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) { - final boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false); - if (!replacing) { - String[] packages = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); - enqueuePackageUpdated(new PackageUpdatedTask( - PackageUpdatedTask.OP_UNAVAILABLE, packages)); - } - // else, we are replacing the packages, so ignore this event and wait for - // EXTERNAL_APPLICATIONS_AVAILABLE to update the packages at that time - } else if (Intent.ACTION_LOCALE_CHANGED.equals(action)) { + /** + * Call from the handler for ACTION_PACKAGE_ADDED, ACTION_PACKAGE_REMOVED and + * ACTION_PACKAGE_CHANGED. + */ + @Override + public void onReceive(Context context, Intent intent) { + if (DEBUG_RECEIVER) Log.d(TAG, "onReceive intent=" + intent); + + final String action = intent.getAction(); + if (Intent.ACTION_LOCALE_CHANGED.equals(action)) { // If we have changed locale we need to clear out the labels in all apps/workspace. forceReload(); } else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) { @@ -1229,7 +1331,7 @@ public class LauncherModel extends BroadcastReceiver { } } - private void forceReload() { + void forceReload() { resetLoadedState(true, true); // Do this here because if the launcher activity is running it will be restarted. @@ -1284,6 +1386,10 @@ public class LauncherModel extends BroadcastReceiver { return isLaunching; } + public boolean isCurrentCallbacks(Callbacks callbacks) { + return (mCallbacks != null && mCallbacks.get() == callbacks); + } + public void startLoader(boolean isLaunching, int synchronousBindPage) { startLoader(isLaunching, synchronousBindPage, LOADER_FLAG_NONE); } @@ -1296,7 +1402,9 @@ public class LauncherModel extends BroadcastReceiver { // Clear any deferred bind-runnables from the synchronized load process // We must do this before any loading/binding is scheduled below. - mDeferredBindRunnables.clear(); + synchronized (mDeferredBindRunnables) { + mDeferredBindRunnables.clear(); + } // Don't bother to start the thread if we know it's not going to do anything if (mCallbacks != null && mCallbacks.get() != null) { @@ -1318,10 +1426,15 @@ public class LauncherModel extends BroadcastReceiver { void bindRemainingSynchronousPages() { // Post the remaining side pages to be loaded if (!mDeferredBindRunnables.isEmpty()) { - for (final Runnable r : mDeferredBindRunnables) { + Runnable[] deferredBindRunnables = null; + synchronized (mDeferredBindRunnables) { + deferredBindRunnables = mDeferredBindRunnables.toArray( + new Runnable[mDeferredBindRunnables.size()]); + mDeferredBindRunnables.clear(); + } + for (final Runnable r : deferredBindRunnables) { mHandler.post(r, MAIN_THREAD_BINDING_RUNNABLE); } - mDeferredBindRunnables.clear(); } } @@ -1630,7 +1743,7 @@ public class LauncherModel extends BroadcastReceiver { ArrayList<ItemInfo> added = new ArrayList<ItemInfo>(); synchronized (sBgLock) { for (AppInfo app : mBgAllAppsList.data) { - tmpInfos = getItemInfoForComponentName(app.componentName); + tmpInfos = getItemInfoForComponentName(app.componentName, app.user); if (tmpInfos.isEmpty()) { // We are missing an application icon, so add this to the workspace added.add(app); @@ -1760,6 +1873,9 @@ public class LauncherModel extends BroadcastReceiver { final PackageManager manager = context.getPackageManager(); final AppWidgetManager widgets = AppWidgetManager.getInstance(context); final boolean isSafeMode = manager.isSafeMode(); + final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(context); + final boolean isSdCardReady = context.registerReceiver(null, + new IntentFilter(StartupReceiver.SYSTEM_READY)) != null; LauncherAppState app = LauncherAppState.getInstance(); DeviceProfile grid = app.getDynamicGrid().getDeviceProfile(); @@ -1778,22 +1894,23 @@ public class LauncherModel extends BroadcastReceiver { } else { // Make sure the default workspace is loaded Launcher.addDumpLog(TAG, "loadWorkspace: loading default favorites", false); - LauncherAppState.getLauncherProvider().loadDefaultFavoritesIfNecessary(0); + LauncherAppState.getLauncherProvider().loadDefaultFavoritesIfNecessary(); } - // Check if we need to do any upgrade-path logic - // (Includes having just imported default favorites) - boolean loadedOldDb = LauncherAppState.getLauncherProvider().justLoadedOldDb(); + // This code path is for our old migration code and should no longer be exercised + boolean loadedOldDb = false; // Log to disk Launcher.addDumpLog(TAG, "11683562 - loadedOldDb: " + loadedOldDb, true); synchronized (sBgLock) { clearSBgDataStructures(); + final HashSet<String> installingPkgs = PackageInstallerCompat + .getInstance(mContext).updateAndGetActiveSessionCache(); final ArrayList<Long> itemsToRemove = new ArrayList<Long>(); final ArrayList<Long> restoredRows = new ArrayList<Long>(); - final Uri contentUri = LauncherSettings.Favorites.CONTENT_URI; + final Uri contentUri = LauncherSettings.Favorites.CONTENT_URI_NO_NOTIFICATION; if (DEBUG_LOADERS) Log.d(TAG, "loading model from " + contentUri); final Cursor c = contentResolver.query(contentUri, null, null, null, null); @@ -1835,6 +1952,8 @@ public class LauncherModel extends BroadcastReceiver { LauncherSettings.Favorites.SPANY); final int restoredIndex = c.getColumnIndexOrThrow( LauncherSettings.Favorites.RESTORED); + final int profileIdIndex = c.getColumnIndexOrThrow( + LauncherSettings.Favorites.PROFILE_ID); //final int uriIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.URI); //final int displayModeIndex = c.getColumnIndexOrThrow( // LauncherSettings.Favorites.DISPLAY_MODE); @@ -1845,43 +1964,119 @@ public class LauncherModel extends BroadcastReceiver { int container; long id; Intent intent; + UserHandleCompat user; while (!mStopped && c.moveToNext()) { AtomicBoolean deleteOnInvalidPlacement = new AtomicBoolean(false); try { int itemType = c.getInt(itemTypeIndex); boolean restored = 0 != c.getInt(restoredIndex); + boolean allowMissingTarget = false; switch (itemType) { case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION: case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT: id = c.getLong(idIndex); intentDescription = c.getString(intentIndex); + long serialNumber = c.getInt(profileIdIndex); + user = mUserManager.getUserForSerialNumber(serialNumber); + int promiseType = c.getInt(restoredIndex); + if (user == null) { + // User has been deleted remove the item. + itemsToRemove.add(id); + continue; + } try { intent = Intent.parseUri(intentDescription, 0); ComponentName cn = intent.getComponent(); - if (cn != null && !isValidPackageComponent(manager, cn)) { - if (restored) { - // might be installed later - Launcher.addDumpLog(TAG, - "package not yet restored: " + cn, true); - } else { - if (!mAppsCanBeOnRemoveableStorage) { - // Log the invalid package, and remove it + if (cn != null && cn.getPackageName() != null) { + boolean validPkg = launcherApps.isPackageEnabledForProfile( + cn.getPackageName(), user); + boolean validComponent = validPkg && + launcherApps.isActivityEnabledForProfile(cn, user); + + if (validComponent) { + if (restored) { + // no special handling necessary for this item + restoredRows.add(id); + restored = false; + } + } else if (validPkg) { + intent = null; + if ((promiseType & ShortcutInfo.FLAG_AUTOINTALL_ICON) != 0) { + // We allow auto install apps to have their intent + // updated after an install. + intent = manager.getLaunchIntentForPackage( + cn.getPackageName()); + if (intent != null) { + ContentValues values = new ContentValues(); + values.put(LauncherSettings.Favorites.INTENT, + intent.toUri(0)); + String where = BaseColumns._ID + "= ?"; + String[] args = {Long.toString(id)}; + contentResolver.update(contentUri, values, where, args); + } + } + + if (intent == null) { + // The app is installed but the component is no + // longer available. Launcher.addDumpLog(TAG, - "Invalid package removed: " + cn, true); + "Invalid component removed: " + cn, true); itemsToRemove.add(id); + continue; } else { - // If apps can be on external storage, then we just - // leave them for the user to remove (maybe add - // visual treatment to it) + // no special handling necessary for this item + restoredRows.add(id); + restored = false; + } + } else if (restored) { + // Package is not yet available but might be + // installed later. + Launcher.addDumpLog(TAG, + "package not yet restored: " + cn, true); + + if ((promiseType & ShortcutInfo.FLAG_RESTORE_STARTED) != 0) { + // Restore has started once. + } else if (installingPkgs.contains(cn.getPackageName())) { + // App restore has started. Update the flag + promiseType |= ShortcutInfo.FLAG_RESTORE_STARTED; + ContentValues values = new ContentValues(); + values.put(LauncherSettings.Favorites.RESTORED, + promiseType); + String where = BaseColumns._ID + "= ?"; + String[] args = {Long.toString(id)}; + contentResolver.update(contentUri, values, where, args); + + } else if (REMOVE_UNRESTORED_ICONS) { Launcher.addDumpLog(TAG, - "Invalid package found: " + cn, true); + "Unrestored package removed: " + cn, true); + itemsToRemove.add(id); + continue; } + } else if (isSdCardReady) { + // Do not wait for external media load anymore. + // Log the invalid package, and remove it + Launcher.addDumpLog(TAG, + "Invalid package removed: " + cn, true); + itemsToRemove.add(id); continue; + } else { + // SdCard is not ready yet. Package might get available, + // once it is ready. + Launcher.addDumpLog(TAG, "Invalid package: " + cn + + " (check again later)", true); + HashSet<String> pkgs = sPendingPackages.get(user); + if (pkgs == null) { + pkgs = new HashSet<String>(); + sPendingPackages.put(user, pkgs); + } + pkgs.add(cn.getPackageName()); + allowMissingTarget = true; + // Add the icon on the workspace anyway. } - } else if (restored) { - // no special handling necessary for this restored item + } else if (cn == null) { + // For shortcuts with no component, keep them as they are restoredRows.add(id); restored = false; } @@ -1892,15 +2087,21 @@ public class LauncherModel extends BroadcastReceiver { } if (restored) { - Launcher.addDumpLog(TAG, - "constructing info for partially restored package", - true); - info = getRestoredItemInfo(c, titleIndex, intent); - intent = getRestoredItemIntent(c, context, intent); + if (user.equals(UserHandleCompat.myUserHandle())) { + Launcher.addDumpLog(TAG, + "constructing info for partially restored package", + true); + info = getRestoredItemInfo(c, titleIndex, intent, promiseType); + intent = getRestoredItemIntent(c, context, intent); + } else { + // Don't restore items for other profiles. + itemsToRemove.add(id); + continue; + } } else if (itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) { - info = getShortcutInfo(manager, intent, context, c, iconIndex, - titleIndex, mLabelCache); + info = getShortcutInfo(manager, intent, user, context, c, + iconIndex, titleIndex, mLabelCache, allowMissingTarget); } else { info = getShortcutInfo(c, context, iconTypeIndex, iconPackageIndex, iconResourceIndex, iconIndex, @@ -1929,6 +2130,9 @@ public class LauncherModel extends BroadcastReceiver { info.cellY = c.getInt(cellYIndex); info.spanX = 1; info.spanY = 1; + info.intent.putExtra(ItemInfo.EXTRA_PROFILE, serialNumber); + info.isDisabled = isSafeMode + && !Utilities.isSystemApp(context, intent); // check & update map of what's occupied deleteOnInvalidPlacement.set(false); @@ -2005,31 +2209,79 @@ public class LauncherModel extends BroadcastReceiver { // Read all Launcher-specific widget details int appWidgetId = c.getInt(appWidgetIdIndex); String savedProvider = c.getString(appWidgetProviderIndex); - id = c.getLong(idIndex); + final ComponentName component = + ComponentName.unflattenFromString(savedProvider); + + final int restoreStatus = c.getInt(restoredIndex); + final boolean isIdValid = (restoreStatus & + LauncherAppWidgetInfo.FLAG_ID_NOT_VALID) == 0; - final AppWidgetProviderInfo provider = - widgets.getAppWidgetInfo(appWidgetId); + final boolean wasProviderReady = (restoreStatus & + LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY) == 0; - if (!isSafeMode && (provider == null || provider.provider == null || - provider.provider.getPackageName() == null)) { - String log = "Deleting widget that isn't installed anymore: id=" - + id + " appWidgetId=" + appWidgetId; + final AppWidgetProviderInfo provider = isIdValid + ? widgets.getAppWidgetInfo(appWidgetId) + : findAppWidgetProviderInfoWithComponent(context, component); + + final boolean isProviderReady = isValidProvider(provider); + if (!isSafeMode && wasProviderReady && !isProviderReady) { + String log = "Deleting widget that isn't installed anymore: " + + "id=" + id + " appWidgetId=" + appWidgetId; Log.e(TAG, log); Launcher.addDumpLog(TAG, log, false); itemsToRemove.add(id); } else { - appWidgetInfo = new LauncherAppWidgetInfo(appWidgetId, - provider.provider); + if (isProviderReady) { + appWidgetInfo = new LauncherAppWidgetInfo(appWidgetId, + provider.provider); + int[] minSpan = + Launcher.getMinSpanForWidget(context, provider); + appWidgetInfo.minSpanX = minSpan[0]; + appWidgetInfo.minSpanY = minSpan[1]; + + int status = restoreStatus; + if (!wasProviderReady) { + // If provider was not previously ready, update the + // status and UI flag. + + // Id would be valid only if the widget restore broadcast was received. + if (isIdValid) { + status = LauncherAppWidgetInfo.RESTORE_COMPLETED; + } else { + status &= ~LauncherAppWidgetInfo + .FLAG_PROVIDER_NOT_READY; + } + } + appWidgetInfo.restoreStatus = status; + } else { + Log.v(TAG, "Widget restore pending id=" + id + + " appWidgetId=" + appWidgetId + + " status =" + restoreStatus); + appWidgetInfo = new LauncherAppWidgetInfo(appWidgetId, + component); + appWidgetInfo.restoreStatus = restoreStatus; + + if ((restoreStatus & LauncherAppWidgetInfo.FLAG_RESTORE_STARTED) != 0) { + // Restore has started once. + } else if (installingPkgs.contains(component.getPackageName())) { + // App restore has started. Update the flag + appWidgetInfo.restoreStatus |= + LauncherAppWidgetInfo.FLAG_RESTORE_STARTED; + } else if (REMOVE_UNRESTORED_ICONS) { + Launcher.addDumpLog(TAG, + "Unrestored widget removed: " + component, true); + itemsToRemove.add(id); + continue; + } + } + appWidgetInfo.id = id; appWidgetInfo.screenId = c.getInt(screenIndex); appWidgetInfo.cellX = c.getInt(cellXIndex); appWidgetInfo.cellY = c.getInt(cellYIndex); appWidgetInfo.spanX = c.getInt(spanXIndex); appWidgetInfo.spanY = c.getInt(spanYIndex); - int[] minSpan = Launcher.getMinSpanForWidget(context, provider); - appWidgetInfo.minSpanX = minSpan[0]; - appWidgetInfo.minSpanY = minSpan[1]; container = c.getInt(containerIndex); if (container != LauncherSettings.Favorites.CONTAINER_DESKTOP && @@ -2049,13 +2301,17 @@ public class LauncherModel extends BroadcastReceiver { } break; } - String providerName = provider.provider.flattenToString(); - if (!providerName.equals(savedProvider)) { + + String providerName = appWidgetInfo.providerName.flattenToString(); + if (!providerName.equals(savedProvider) || + (appWidgetInfo.restoreStatus != restoreStatus)) { ContentValues values = new ContentValues(); values.put(LauncherSettings.Favorites.APPWIDGET_PROVIDER, providerName); + values.put(LauncherSettings.Favorites.RESTORED, + appWidgetInfo.restoreStatus); String where = BaseColumns._ID + "= ?"; - String[] args = {Integer.toString(c.getInt(idIndex))}; + String[] args = {Long.toString(id)}; contentResolver.update(contentUri, values, where, args); } sBgItemsIdMap.put(appWidgetInfo.id, appWidgetInfo); @@ -2081,7 +2337,7 @@ public class LauncherModel extends BroadcastReceiver { if (itemsToRemove.size() > 0) { ContentProviderClient client = contentResolver.acquireContentProviderClient( - LauncherSettings.Favorites.CONTENT_URI); + contentUri); // Remove dead items for (long id : itemsToRemove) { if (DEBUG_LOADERS) { @@ -2099,7 +2355,7 @@ public class LauncherModel extends BroadcastReceiver { if (restoredRows.size() > 0) { ContentProviderClient updater = contentResolver.acquireContentProviderClient( - LauncherSettings.Favorites.CONTENT_URI); + contentUri); // Update restored items that no longer require special handling try { StringBuilder selectionBuilder = new StringBuilder(); @@ -2109,13 +2365,19 @@ public class LauncherModel extends BroadcastReceiver { selectionBuilder.append(")"); ContentValues values = new ContentValues(); values.put(LauncherSettings.Favorites.RESTORED, 0); - updater.update(LauncherSettings.Favorites.CONTENT_URI, + updater.update(LauncherSettings.Favorites.CONTENT_URI_NO_NOTIFICATION, values, selectionBuilder.toString(), null); } catch (RemoteException e) { Log.w(TAG, "Could not update restored rows"); } } + if (!isSdCardReady && !sPendingPackages.isEmpty()) { + context.registerReceiver(new AppsAvailabilityCheck(), + new IntentFilter(StartupReceiver.SYSTEM_READY), + null, sWorker); + } + if (loadedOldDb) { long maxScreenId = 0; // If we're importing we use the old screen order. @@ -2189,7 +2451,12 @@ public class LauncherModel extends BroadcastReceiver { line += " | "; } for (int x = 0; x < countX; x++) { - line += ((occupied.get(screenId)[x][y] != null) ? "#" : "."); + ItemInfo[][] screen = occupied.get(screenId); + if (x < screen.length && y < screen[x].length) { + line += (screen[x][y] != null) ? "#" : "."; + } else { + line += "!"; + } } } Log.d(TAG, "[ " + line + " ]"); @@ -2343,7 +2610,9 @@ public class LauncherModel extends BroadcastReceiver { } }; if (postOnMainThread) { - deferredBindRunnables.add(r); + synchronized (deferredBindRunnables) { + deferredBindRunnables.add(r); + } } else { runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE); } @@ -2360,7 +2629,9 @@ public class LauncherModel extends BroadcastReceiver { } }; if (postOnMainThread) { - deferredBindRunnables.add(r); + synchronized (deferredBindRunnables) { + deferredBindRunnables.add(r); + } } else { runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE); } @@ -2482,7 +2753,9 @@ public class LauncherModel extends BroadcastReceiver { // Load all the remaining pages (if we are loading synchronously, we want to defer this // work until after the first render) - mDeferredBindRunnables.clear(); + synchronized (mDeferredBindRunnables) { + mDeferredBindRunnables.clear(); + } bindWorkspaceItems(oldCallbacks, otherWorkspaceItems, otherAppWidgets, otherFolders, (isLoadingSynchronously ? mDeferredBindRunnables : null)); @@ -2504,7 +2777,9 @@ public class LauncherModel extends BroadcastReceiver { } }; if (isLoadingSynchronously) { - mDeferredBindRunnables.add(r); + synchronized (mDeferredBindRunnables) { + mDeferredBindRunnables.add(r); + } } else { runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE); } @@ -2570,42 +2845,42 @@ public class LauncherModel extends BroadcastReceiver { return; } - final PackageManager packageManager = mContext.getPackageManager(); final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null); mainIntent.addCategory(Intent.CATEGORY_LAUNCHER); + final List<UserHandleCompat> profiles = mUserManager.getUserProfiles(); + // Clear the list of apps mBgAllAppsList.clear(); + for (UserHandleCompat user : profiles) { + // Query for the set of apps + final long qiaTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0; + List<LauncherActivityInfoCompat> apps = mLauncherApps.getActivityList(null, user); + if (DEBUG_LOADERS) { + Log.d(TAG, "getActivityList took " + + (SystemClock.uptimeMillis()-qiaTime) + "ms for user " + user); + Log.d(TAG, "getActivityList got " + apps.size() + " apps for user " + user); + } + // Fail if we don't have any apps + if (apps == null || apps.isEmpty()) { + return; + } + // Sort the applications by name + final long sortTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0; + Collections.sort(apps, + new LauncherModel.ShortcutNameComparator(mLabelCache)); + if (DEBUG_LOADERS) { + Log.d(TAG, "sort took " + + (SystemClock.uptimeMillis()-sortTime) + "ms"); + } - // Query for the set of apps - final long qiaTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0; - List<ResolveInfo> apps = packageManager.queryIntentActivities(mainIntent, 0); - if (DEBUG_LOADERS) { - Log.d(TAG, "queryIntentActivities took " - + (SystemClock.uptimeMillis()-qiaTime) + "ms"); - Log.d(TAG, "queryIntentActivities got " + apps.size() + " apps"); - } - // Fail if we don't have any apps - if (apps == null || apps.isEmpty()) { - return; - } - // Sort the applications by name - final long sortTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0; - Collections.sort(apps, - new LauncherModel.ShortcutNameComparator(packageManager, mLabelCache)); - if (DEBUG_LOADERS) { - Log.d(TAG, "sort took " - + (SystemClock.uptimeMillis()-sortTime) + "ms"); - } - - // Create the ApplicationInfos - for (int i = 0; i < apps.size(); i++) { - ResolveInfo app = apps.get(i); - // This builds the icon bitmaps. - mBgAllAppsList.add(new AppInfo(packageManager, app, - mIconCache, mLabelCache)); + // Create the ApplicationInfos + for (int i = 0; i < apps.size(); i++) { + LauncherActivityInfoCompat app = apps.get(i); + // This builds the icon bitmaps. + mBgAllAppsList.add(new AppInfo(mContext, app, user, mIconCache, mLabelCache)); + } } - // Huh? Shouldn't this be inside the Runnable below? final ArrayList<AppInfo> added = mBgAllAppsList.added; mBgAllAppsList.added = new ArrayList<AppInfo>(); @@ -2648,9 +2923,95 @@ public class LauncherModel extends BroadcastReceiver { sWorker.post(task); } + private class AppsAvailabilityCheck extends BroadcastReceiver { + + @Override + public void onReceive(Context context, Intent intent) { + synchronized (sBgLock) { + final LauncherAppsCompat launcherApps = LauncherAppsCompat + .getInstance(mApp.getContext()); + ArrayList<String> packagesRemoved; + for (Entry<UserHandleCompat, HashSet<String>> entry : sPendingPackages.entrySet()) { + UserHandleCompat user = entry.getKey(); + packagesRemoved = new ArrayList<String>(); + for (String pkg : entry.getValue()) { + if (!launcherApps.isPackageEnabledForProfile(pkg, user)) { + Launcher.addDumpLog(TAG, "Package not found: " + pkg, true); + packagesRemoved.add(pkg); + } + } + if (!packagesRemoved.isEmpty()) { + enqueuePackageUpdated(new PackageUpdatedTask(PackageUpdatedTask.OP_REMOVE, + packagesRemoved.toArray(new String[packagesRemoved.size()]), user)); + } + } + sPendingPackages.clear(); + } + } + } + + /** + * Workaround to re-check unrestored items, in-case they were installed but the Package-ADD + * runnable was missed by the launcher. + */ + public void recheckRestoredItems(final Context context) { + Runnable r = new Runnable() { + + @Override + public void run() { + LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(context); + HashSet<String> installedPackages = new HashSet<String>(); + UserHandleCompat user = UserHandleCompat.myUserHandle(); + synchronized(sBgLock) { + for (ItemInfo info : sBgItemsIdMap.values()) { + if (info instanceof ShortcutInfo) { + ShortcutInfo si = (ShortcutInfo) info; + if (si.isPromise() && si.getTargetComponent() != null + && launcherApps.isPackageEnabledForProfile( + si.getTargetComponent().getPackageName(), user)) { + installedPackages.add(si.getTargetComponent().getPackageName()); + } + } else if (info instanceof LauncherAppWidgetInfo) { + LauncherAppWidgetInfo widget = (LauncherAppWidgetInfo) info; + if (widget.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY) + && launcherApps.isPackageEnabledForProfile( + widget.providerName.getPackageName(), user)) { + installedPackages.add(widget.providerName.getPackageName()); + } + } + } + } + + if (!installedPackages.isEmpty()) { + final ArrayList<AppInfo> restoredApps = new ArrayList<AppInfo>(); + for (String pkg : installedPackages) { + for (LauncherActivityInfoCompat info : launcherApps.getActivityList(pkg, user)) { + restoredApps.add(new AppInfo(context, info, user, mIconCache, null)); + } + } + + final Callbacks callbacks = mCallbacks != null ? mCallbacks.get() : null; + if (!restoredApps.isEmpty()) { + mHandler.post(new Runnable() { + public void run() { + Callbacks cb = mCallbacks != null ? mCallbacks.get() : null; + if (callbacks == cb && cb != null) { + callbacks.bindAppsRestored(restoredApps); + } + } + }); + } + + } + } + }; + sWorker.post(r); + } + private class PackageUpdatedTask implements Runnable { int mOp; String[] mPackages; + UserHandleCompat mUser; public static final int OP_NONE = 0; public static final int OP_ADD = 1; @@ -2659,9 +3020,10 @@ public class LauncherModel extends BroadcastReceiver { public static final int OP_UNAVAILABLE = 4; // external media unmounted - public PackageUpdatedTask(int op, String[] packages) { + public PackageUpdatedTask(int op, String[] packages, UserHandleCompat user) { mOp = op; mPackages = packages; + mUser = user; } public void run() { @@ -2673,14 +3035,14 @@ public class LauncherModel extends BroadcastReceiver { case OP_ADD: for (int i=0; i<N; i++) { if (DEBUG_LOADERS) Log.d(TAG, "mAllAppsList.addPackage " + packages[i]); - mIconCache.remove(packages[i]); - mBgAllAppsList.addPackage(context, packages[i]); + mIconCache.remove(packages[i], mUser); + mBgAllAppsList.addPackage(context, packages[i], mUser); } break; case OP_UPDATE: for (int i=0; i<N; i++) { if (DEBUG_LOADERS) Log.d(TAG, "mAllAppsList.updatePackage " + packages[i]); - mBgAllAppsList.updatePackage(context, packages[i]); + mBgAllAppsList.updatePackage(context, packages[i], mUser); WidgetPreviewLoader.removePackageFromDb( mApp.getWidgetPreviewCacheDb(), packages[i]); } @@ -2689,7 +3051,7 @@ public class LauncherModel extends BroadcastReceiver { case OP_UNAVAILABLE: for (int i=0; i<N; i++) { if (DEBUG_LOADERS) Log.d(TAG, "mAllAppsList.removePackage " + packages[i]); - mBgAllAppsList.removePackage(packages[i]); + mBgAllAppsList.removePackage(packages[i], mUser); WidgetPreviewLoader.removePackageFromDb( mApp.getWidgetPreviewCacheDb(), packages[i]); } @@ -2735,11 +3097,12 @@ public class LauncherModel extends BroadcastReceiver { // Update the launcher db to reflect the changes for (AppInfo a : modifiedFinal) { ArrayList<ItemInfo> infos = - getItemInfoForComponentName(a.componentName); + getItemInfoForComponentName(a.componentName, mUser); for (ItemInfo i : infos) { if (isShortcutInfoUpdateable(i)) { ShortcutInfo info = (ShortcutInfo) i; info.title = a.title.toString(); + info.contentDescription = a.contentDescription; updateItemInDatabase(context, info); } } @@ -2764,24 +3127,19 @@ public class LauncherModel extends BroadcastReceiver { // Mark disabled packages in the broadcast to be removed final PackageManager pm = context.getPackageManager(); for (int i=0; i<N; i++) { - if (isPackageDisabled(pm, packages[i])) { + if (isPackageDisabled(context, packages[i], mUser)) { removedPackageNames.add(packages[i]); } } } // Remove all the components associated with this package for (String pn : removedPackageNames) { - ArrayList<ItemInfo> infos = getItemInfoForPackageName(pn); - for (ItemInfo i : infos) { - deleteItemFromDatabase(context, i); - } + deletePackageFromDatabase(context, pn, mUser); } // Remove all the specific components for (AppInfo a : removedApps) { - ArrayList<ItemInfo> infos = getItemInfoForComponentName(a.componentName); - for (ItemInfo i : infos) { - deleteItemFromDatabase(context, i); - } + ArrayList<ItemInfo> infos = getItemInfoForComponentName(a.componentName, mUser); + deleteItemsFromDatabase(context, infos); } if (!removedPackageNames.isEmpty() || !removedApps.isEmpty()) { // Remove any queued items from the install queue @@ -2794,14 +3152,14 @@ public class LauncherModel extends BroadcastReceiver { public void run() { Callbacks cb = mCallbacks != null ? mCallbacks.get() : null; if (callbacks == cb && cb != null) { - callbacks.bindComponentsRemoved(removedPackageNames, removedApps); + callbacks.bindComponentsRemoved(removedPackageNames, removedApps, mUser); } } }); } final ArrayList<Object> widgetsAndShortcuts = - getSortedWidgetsAndShortcuts(context); + getSortedWidgetsAndShortcuts(context); mHandler.post(new Runnable() { @Override public void run() { @@ -2828,55 +3186,70 @@ public class LauncherModel extends BroadcastReceiver { public static ArrayList<Object> getSortedWidgetsAndShortcuts(Context context) { PackageManager packageManager = context.getPackageManager(); final ArrayList<Object> widgetsAndShortcuts = new ArrayList<Object>(); - widgetsAndShortcuts.addAll(AppWidgetManager.getInstance(context).getInstalledProviders()); + widgetsAndShortcuts.addAll(AppWidgetManagerCompat.getInstance(context).getAllProviders()); + Intent shortcutsIntent = new Intent(Intent.ACTION_CREATE_SHORTCUT); widgetsAndShortcuts.addAll(packageManager.queryIntentActivities(shortcutsIntent, 0)); - Collections.sort(widgetsAndShortcuts, - new LauncherModel.WidgetAndShortcutNameComparator(packageManager)); + Collections.sort(widgetsAndShortcuts, new WidgetAndShortcutNameComparator(context)); return widgetsAndShortcuts; } - private static boolean isPackageDisabled(PackageManager pm, String packageName) { - try { - PackageInfo pi = pm.getPackageInfo(packageName, 0); - return !pi.applicationInfo.enabled; - } catch (NameNotFoundException e) { - // Fall through - } - return false; + private static boolean isPackageDisabled(Context context, String packageName, + UserHandleCompat user) { + final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(context); + return !launcherApps.isPackageEnabledForProfile(packageName, user); } - public static boolean isValidPackageComponent(PackageManager pm, ComponentName cn) { + public static boolean isValidPackageActivity(Context context, ComponentName cn, + UserHandleCompat user) { if (cn == null) { return false; } - if (isPackageDisabled(pm, cn.getPackageName())) { + final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(context); + if (!launcherApps.isPackageEnabledForProfile(cn.getPackageName(), user)) { return false; } + return launcherApps.isActivityEnabledForProfile(cn, user); + } - try { - // Check the activity - PackageInfo pi = pm.getPackageInfo(cn.getPackageName(), 0); - return (pm.getActivityInfo(cn, 0) != null); - } catch (NameNotFoundException e) { + public static boolean isValidPackage(Context context, String packageName, + UserHandleCompat user) { + if (packageName == null) { return false; } + final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(context); + return launcherApps.isPackageEnabledForProfile(packageName, user); } /** * Make an ShortcutInfo object for a restored application or shortcut item that points * to a package that is not yet installed on the system. */ - public ShortcutInfo getRestoredItemInfo(Cursor cursor, int titleIndex, Intent intent) { + public ShortcutInfo getRestoredItemInfo(Cursor cursor, int titleIndex, Intent intent, + int promiseType) { final ShortcutInfo info = new ShortcutInfo(); - if (cursor != null) { - info.title = cursor.getString(titleIndex); + info.user = UserHandleCompat.myUserHandle(); + mIconCache.getTitleAndIcon(info, intent, info.user, true); + + if ((promiseType & ShortcutInfo.FLAG_RESTORED_ICON) != 0) { + String title = (cursor != null) ? cursor.getString(titleIndex) : null; + if (!TextUtils.isEmpty(title)) { + info.title = title; + } + info.status = ShortcutInfo.FLAG_RESTORED_ICON; + } else if ((promiseType & ShortcutInfo.FLAG_AUTOINTALL_ICON) != 0) { + if (TextUtils.isEmpty(info.title)) { + info.title = (cursor != null) ? cursor.getString(titleIndex) : ""; + } + info.status = ShortcutInfo.FLAG_AUTOINTALL_ICON; } else { - info.title = ""; + throw new InvalidParameterException("Invalid restoreType " + promiseType); } - info.setIcon(mIconCache.getIcon(intent, info.title.toString())); + + info.contentDescription = mUserManager.getBadgedLabelForUser( + info.title.toString(), info.user); info.itemType = LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT; - info.restoredIntent = intent; + info.promisedIntent = intent; return info; } @@ -2885,25 +3258,26 @@ public class LauncherModel extends BroadcastReceiver { * to the market page for the item. */ private Intent getRestoredItemIntent(Cursor c, Context context, Intent intent) { - final boolean debug = false; ComponentName componentName = intent.getComponent(); - Intent marketIntent = new Intent(Intent.ACTION_VIEW); - Uri marketUri = new Uri.Builder() + return getMarketIntent(componentName.getPackageName()); + } + + static Intent getMarketIntent(String packageName) { + return new Intent(Intent.ACTION_VIEW) + .setData(new Uri.Builder() .scheme("market") .authority("details") - .appendQueryParameter("id", componentName.getPackageName()) - .build(); - if (debug) Log.d(TAG, "manufactured intent uri: " + marketUri.toString()); - marketIntent.setData(marketUri); - return marketIntent; + .appendQueryParameter("id", packageName) + .build()); } /** * This is called from the code that adds shortcuts from the intent receiver. This * doesn't have a Cursor, but */ - public ShortcutInfo getShortcutInfo(PackageManager manager, Intent intent, Context context) { - return getShortcutInfo(manager, intent, context, null, -1, -1, null); + public ShortcutInfo getShortcutInfo(PackageManager manager, Intent intent, + UserHandleCompat user, Context context) { + return getShortcutInfo(manager, intent, user, context, null, -1, -1, null, false); } /** @@ -2911,54 +3285,37 @@ public class LauncherModel extends BroadcastReceiver { * * If c is not null, then it will be used to fill in missing data like the title and icon. */ - public ShortcutInfo getShortcutInfo(PackageManager manager, Intent intent, Context context, - Cursor c, int iconIndex, int titleIndex, HashMap<Object, CharSequence> labelCache) { + public ShortcutInfo getShortcutInfo(PackageManager manager, Intent intent, + UserHandleCompat user, Context context, Cursor c, int iconIndex, int titleIndex, + HashMap<Object, CharSequence> labelCache, boolean allowMissingTarget) { + if (user == null) { + Log.d(TAG, "Null user found in getShortcutInfo"); + return null; + } + ComponentName componentName = intent.getComponent(); - final ShortcutInfo info = new ShortcutInfo(); - if (componentName != null && !isValidPackageComponent(manager, componentName)) { - Log.d(TAG, "Invalid package found in getShortcutInfo: " + componentName); + if (componentName == null) { + Log.d(TAG, "Missing component found in getShortcutInfo: " + componentName); + return null; + } + + Intent newIntent = new Intent(intent.getAction(), null); + newIntent.addCategory(Intent.CATEGORY_LAUNCHER); + newIntent.setComponent(componentName); + LauncherActivityInfoCompat lai = mLauncherApps.resolveActivity(newIntent, user); + if ((lai == null) && !allowMissingTarget) { + Log.d(TAG, "Missing activity found in getShortcutInfo: " + componentName); return null; - } else { - try { - PackageInfo pi = manager.getPackageInfo(componentName.getPackageName(), 0); - info.initFlagsAndFirstInstallTime(pi); - } catch (NameNotFoundException e) { - Log.d(TAG, "getPackInfo failed for package " + - componentName.getPackageName()); - } } - // TODO: See if the PackageManager knows about this case. If it doesn't - // then return null & delete this. + final ShortcutInfo info = new ShortcutInfo(); // the resource -- This may implicitly give us back the fallback icon, // but don't worry about that. All we're doing with usingFallbackIcon is // to avoid saving lots of copies of that in the database, and most apps // have icons anyway. + Bitmap icon = mIconCache.getIcon(componentName, lai, labelCache); - // Attempt to use queryIntentActivities to get the ResolveInfo (with IntentFilter info) and - // if that fails, or is ambiguious, fallback to the standard way of getting the resolve info - // via resolveActivity(). - Bitmap icon = null; - ResolveInfo resolveInfo = null; - ComponentName oldComponent = intent.getComponent(); - Intent newIntent = new Intent(intent.getAction(), null); - newIntent.addCategory(Intent.CATEGORY_LAUNCHER); - newIntent.setPackage(oldComponent.getPackageName()); - List<ResolveInfo> infos = manager.queryIntentActivities(newIntent, 0); - for (ResolveInfo i : infos) { - ComponentName cn = new ComponentName(i.activityInfo.packageName, - i.activityInfo.name); - if (cn.equals(oldComponent)) { - resolveInfo = i; - } - } - if (resolveInfo == null) { - resolveInfo = manager.resolveActivity(intent, 0); - } - if (resolveInfo != null) { - icon = mIconCache.getIcon(componentName, resolveInfo, labelCache); - } // the db if (icon == null) { if (c != null) { @@ -2967,21 +3324,21 @@ public class LauncherModel extends BroadcastReceiver { } // the fallback icon if (icon == null) { - icon = getFallbackIcon(); + icon = mIconCache.getDefaultIcon(user); info.usingFallbackIcon = true; } info.setIcon(icon); + // From the cache. + if (labelCache != null) { + info.title = labelCache.get(componentName); + } + // from the resource - if (resolveInfo != null) { - ComponentName key = LauncherModel.getComponentNameFromResolveInfo(resolveInfo); - if (labelCache != null && labelCache.containsKey(key)) { - info.title = labelCache.get(key); - } else { - info.title = resolveInfo.activityInfo.loadLabel(manager); - if (labelCache != null) { - labelCache.put(key, info.title); - } + if (info.title == null && lai != null) { + info.title = lai.getLabel(); + if (labelCache != null) { + labelCache.put(componentName, info.title); } } // from the db @@ -2995,6 +3352,9 @@ public class LauncherModel extends BroadcastReceiver { info.title = componentName.getClassName(); } info.itemType = LauncherSettings.Favorites.ITEM_TYPE_APPLICATION; + info.user = user; + info.contentDescription = mUserManager.getBadgedLabelForUser( + info.title.toString(), info.user); return info; } @@ -3004,14 +3364,14 @@ public class LauncherModel extends BroadcastReceiver { for (ItemInfo i : infos) { if (i instanceof ShortcutInfo) { ShortcutInfo info = (ShortcutInfo) i; - ComponentName cn = info.intent.getComponent(); + ComponentName cn = info.getTargetComponent(); if (cn != null && f.filterItem(null, info, cn)) { filtered.add(info); } } else if (i instanceof FolderInfo) { FolderInfo info = (FolderInfo) i; for (ShortcutInfo s : info.contents) { - ComponentName cn = s.intent.getComponent(); + ComponentName cn = s.getTargetComponent(); if (cn != null && f.filterItem(info, s, cn)) { filtered.add(s); } @@ -3027,21 +3387,16 @@ public class LauncherModel extends BroadcastReceiver { return new ArrayList<ItemInfo>(filtered); } - private ArrayList<ItemInfo> getItemInfoForPackageName(final String pn) { + private ArrayList<ItemInfo> getItemInfoForComponentName(final ComponentName cname, + final UserHandleCompat user) { ItemInfoFilter filter = new ItemInfoFilter() { @Override public boolean filterItem(ItemInfo parent, ItemInfo info, ComponentName cn) { - return cn.getPackageName().equals(pn); - } - }; - return filterItemInfos(sBgItemsIdMap.values(), filter); - } - - private ArrayList<ItemInfo> getItemInfoForComponentName(final ComponentName cname) { - ItemInfoFilter filter = new ItemInfoFilter() { - @Override - public boolean filterItem(ItemInfo parent, ItemInfo info, ComponentName cn) { - return cn.equals(cname); + if (info.user == null) { + return cn.equals(cname); + } else { + return cn.equals(cname) && info.user.equals(user); + } } }; return filterItemInfos(sBgItemsIdMap.values(), filter); @@ -3060,7 +3415,7 @@ public class LauncherModel extends BroadcastReceiver { return true; } // placeholder shortcuts get special treatment, let them through too. - if (info.getRestoredIntent() != null) { + if (info.isPromise()) { return true; } } @@ -3076,6 +3431,8 @@ public class LauncherModel extends BroadcastReceiver { Bitmap icon = null; final ShortcutInfo info = new ShortcutInfo(); + // Non-app shortcuts are only supported for current user. + info.user = UserHandleCompat.myUserHandle(); info.itemType = LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT; // TODO: If there's an explicit component and we can't install that, delete it. @@ -3106,14 +3463,14 @@ public class LauncherModel extends BroadcastReceiver { } // the fallback icon if (icon == null) { - icon = getFallbackIcon(); + icon = mIconCache.getDefaultIcon(info.user); info.usingFallbackIcon = true; } break; case LauncherSettings.Favorites.ICON_TYPE_BITMAP: icon = getIconFromCursor(c, iconIndex, context); if (icon == null) { - icon = getFallbackIcon(); + icon = mIconCache.getDefaultIcon(info.user); info.customIcon = false; info.usingFallbackIcon = true; } else { @@ -3121,7 +3478,7 @@ public class LauncherModel extends BroadcastReceiver { } break; default: - icon = getFallbackIcon(); + icon = mIconCache.getDefaultIcon(info.user); info.usingFallbackIcon = true; info.customIcon = false; break; @@ -3160,7 +3517,7 @@ public class LauncherModel extends BroadcastReceiver { /** * Attempts to find an AppWidgetProviderInfo that matches the given component. */ - AppWidgetProviderInfo findAppWidgetProviderInfoWithComponent(Context context, + static AppWidgetProviderInfo findAppWidgetProviderInfoWithComponent(Context context, ComponentName component) { List<AppWidgetProviderInfo> widgets = AppWidgetManager.getInstance(context).getInstalledProviders(); @@ -3172,44 +3529,6 @@ public class LauncherModel extends BroadcastReceiver { return null; } - /** - * Returns a list of all the widgets that can handle configuration with a particular mimeType. - */ - List<WidgetMimeTypeHandlerData> resolveWidgetsForMimeType(Context context, String mimeType) { - final PackageManager packageManager = context.getPackageManager(); - final List<WidgetMimeTypeHandlerData> supportedConfigurationActivities = - new ArrayList<WidgetMimeTypeHandlerData>(); - - final Intent supportsIntent = - new Intent(InstallWidgetReceiver.ACTION_SUPPORTS_CLIPDATA_MIMETYPE); - supportsIntent.setType(mimeType); - - // Create a set of widget configuration components that we can test against - final List<AppWidgetProviderInfo> widgets = - AppWidgetManager.getInstance(context).getInstalledProviders(); - final HashMap<ComponentName, AppWidgetProviderInfo> configurationComponentToWidget = - new HashMap<ComponentName, AppWidgetProviderInfo>(); - for (AppWidgetProviderInfo info : widgets) { - configurationComponentToWidget.put(info.configure, info); - } - - // Run through each of the intents that can handle this type of clip data, and cross - // reference them with the components that are actual configuration components - final List<ResolveInfo> activities = packageManager.queryIntentActivities(supportsIntent, - PackageManager.MATCH_DEFAULT_ONLY); - for (ResolveInfo info : activities) { - final ActivityInfo activityInfo = info.activityInfo; - final ComponentName infoComponent = new ComponentName(activityInfo.packageName, - activityInfo.name); - if (configurationComponentToWidget.containsKey(infoComponent)) { - supportedConfigurationActivities.add( - new InstallWidgetReceiver.WidgetMimeTypeHandlerData(info, - configurationComponentToWidget.get(infoComponent))); - } - } - return supportedConfigurationActivities; - } - ShortcutInfo infoFromShortcutIntent(Context context, Intent data, Bitmap fallbackIcon) { Intent intent = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_INTENT); String name = data.getStringExtra(Intent.EXTRA_SHORTCUT_NAME); @@ -3238,7 +3557,8 @@ public class LauncherModel extends BroadcastReceiver { iconResource.packageName); final int id = resources.getIdentifier(iconResource.resourceName, null, null); icon = Utilities.createIconBitmap( - mIconCache.getFullResIcon(resources, id), context); + mIconCache.getFullResIcon(resources, id), + context); } catch (Exception e) { Log.w(TAG, "Could not load shortcut icon: " + extra); } @@ -3247,17 +3567,22 @@ public class LauncherModel extends BroadcastReceiver { final ShortcutInfo info = new ShortcutInfo(); + // Only support intents for current user for now. Intents sent from other + // users wouldn't get here without intent forwarding anyway. + info.user = UserHandleCompat.myUserHandle(); if (icon == null) { if (fallbackIcon != null) { icon = fallbackIcon; } else { - icon = getFallbackIcon(); + icon = mIconCache.getDefaultIcon(info.user); info.usingFallbackIcon = true; } } info.setIcon(icon); info.title = name; + info.contentDescription = mUserManager.getBadgedLabelForUser( + info.title.toString(), info.user); info.intent = intent; info.customIcon = customIcon; info.iconResource = iconResource; @@ -3323,12 +3648,18 @@ public class LauncherModel extends BroadcastReceiver { final Collator collator = Collator.getInstance(); return new Comparator<AppInfo>() { public final int compare(AppInfo a, AppInfo b) { - int result = collator.compare(a.title.toString().trim(), - b.title.toString().trim()); - if (result == 0) { - result = a.componentName.compareTo(b.componentName); + if (a.user.equals(b.user)) { + int result = collator.compare(a.title.toString().trim(), + b.title.toString().trim()); + if (result == 0) { + result = a.componentName.compareTo(b.componentName); + } + return result; + } else { + // TODO Need to figure out rules for sorting + // profiles, this puts work second. + return a.user.toString().compareTo(b.user.toString()); } - return result; } }; } @@ -3340,14 +3671,6 @@ public class LauncherModel extends BroadcastReceiver { return 0; } }; - public static final Comparator<AppWidgetProviderInfo> getWidgetNameComparator() { - final Collator collator = Collator.getInstance(); - return new Comparator<AppWidgetProviderInfo>() { - public final int compare(AppWidgetProviderInfo a, AppWidgetProviderInfo b) { - return collator.compare(a.label.toString().trim(), b.label.toString().trim()); - } - }; - } static ComponentName getComponentNameFromResolveInfo(ResolveInfo info) { if (info.activityInfo != null) { return new ComponentName(info.activityInfo.packageName, info.activityInfo.name); @@ -3355,35 +3678,32 @@ public class LauncherModel extends BroadcastReceiver { return new ComponentName(info.serviceInfo.packageName, info.serviceInfo.name); } } - public static class ShortcutNameComparator implements Comparator<ResolveInfo> { + public static class ShortcutNameComparator implements Comparator<LauncherActivityInfoCompat> { private Collator mCollator; - private PackageManager mPackageManager; private HashMap<Object, CharSequence> mLabelCache; ShortcutNameComparator(PackageManager pm) { - mPackageManager = pm; mLabelCache = new HashMap<Object, CharSequence>(); mCollator = Collator.getInstance(); } - ShortcutNameComparator(PackageManager pm, HashMap<Object, CharSequence> labelCache) { - mPackageManager = pm; + ShortcutNameComparator(HashMap<Object, CharSequence> labelCache) { mLabelCache = labelCache; mCollator = Collator.getInstance(); } - public final int compare(ResolveInfo a, ResolveInfo b) { - CharSequence labelA, labelB; - ComponentName keyA = LauncherModel.getComponentNameFromResolveInfo(a); - ComponentName keyB = LauncherModel.getComponentNameFromResolveInfo(b); + public final int compare(LauncherActivityInfoCompat a, LauncherActivityInfoCompat b) { + String labelA, labelB; + ComponentName keyA = a.getComponentName(); + ComponentName keyB = b.getComponentName(); if (mLabelCache.containsKey(keyA)) { - labelA = mLabelCache.get(keyA); + labelA = mLabelCache.get(keyA).toString(); } else { - labelA = a.loadLabel(mPackageManager).toString().trim(); + labelA = a.getLabel().toString().trim(); mLabelCache.put(keyA, labelA); } if (mLabelCache.containsKey(keyB)) { - labelB = mLabelCache.get(keyB); + labelB = mLabelCache.get(keyB).toString(); } else { - labelB = b.loadLabel(mPackageManager).toString().trim(); + labelB = b.getLabel().toString().trim(); mLabelCache.put(keyB, labelB); } @@ -3391,11 +3711,14 @@ public class LauncherModel extends BroadcastReceiver { } }; public static class WidgetAndShortcutNameComparator implements Comparator<Object> { - private Collator mCollator; - private PackageManager mPackageManager; - private HashMap<Object, String> mLabelCache; - WidgetAndShortcutNameComparator(PackageManager pm) { - mPackageManager = pm; + private final AppWidgetManagerCompat mManager; + private final PackageManager mPackageManager; + private final HashMap<Object, String> mLabelCache; + private final Collator mCollator; + + WidgetAndShortcutNameComparator(Context context) { + mManager = AppWidgetManagerCompat.getInstance(context); + mPackageManager = context.getPackageManager(); mLabelCache = new HashMap<Object, String>(); mCollator = Collator.getInstance(); } @@ -3404,23 +3727,28 @@ public class LauncherModel extends BroadcastReceiver { if (mLabelCache.containsKey(a)) { labelA = mLabelCache.get(a); } else { - labelA = (a instanceof AppWidgetProviderInfo) ? - ((AppWidgetProviderInfo) a).label : - ((ResolveInfo) a).loadLabel(mPackageManager).toString().trim(); + labelA = (a instanceof AppWidgetProviderInfo) + ? mManager.loadLabel((AppWidgetProviderInfo) a) + : ((ResolveInfo) a).loadLabel(mPackageManager).toString().trim(); mLabelCache.put(a, labelA); } if (mLabelCache.containsKey(b)) { labelB = mLabelCache.get(b); } else { - labelB = (b instanceof AppWidgetProviderInfo) ? - ((AppWidgetProviderInfo) b).label : - ((ResolveInfo) b).loadLabel(mPackageManager).toString().trim(); + labelB = (b instanceof AppWidgetProviderInfo) + ? mManager.loadLabel((AppWidgetProviderInfo) b) + : ((ResolveInfo) b).loadLabel(mPackageManager).toString().trim(); mLabelCache.put(b, labelB); } return mCollator.compare(labelA, labelB); } }; + static boolean isValidProvider(AppWidgetProviderInfo provider) { + return (provider != null) && (provider.provider != null) + && (provider.provider.getPackageName() != null); + } + public void dumpState() { Log.d(TAG, "mCallbacks=" + mCallbacks); AppInfo.dumpApplicationInfoList(TAG, "mAllAppsList.data", mBgAllAppsList.data); diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java index a080dd8ca..6cc1688de 100644 --- a/src/com/android/launcher3/LauncherProvider.java +++ b/src/com/android/launcher3/LauncherProvider.java @@ -32,9 +32,10 @@ import android.content.Intent; import android.content.OperationApplicationException; import android.content.SharedPreferences; import android.content.pm.ActivityInfo; +import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; import android.content.res.Resources; -import android.content.res.TypedArray; import android.content.res.XmlResourceParser; import android.database.Cursor; import android.database.SQLException; @@ -48,12 +49,13 @@ import android.net.Uri; import android.os.Bundle; import android.provider.Settings; import android.text.TextUtils; -import android.util.AttributeSet; import android.util.Log; import android.util.SparseArray; -import android.util.Xml; +import com.android.launcher3.AutoInstallsLayout.LayoutParserCallback; import com.android.launcher3.LauncherSettings.Favorites; +import com.android.launcher3.compat.UserHandleCompat; +import com.android.launcher3.compat.UserManagerCompat; import com.android.launcher3.config.ProviderConfig; import org.xmlpull.v1.XmlPullParser; @@ -63,6 +65,7 @@ import java.io.File; import java.io.IOException; import java.net.URISyntaxException; import java.util.ArrayList; +import java.util.Collections; import java.util.HashSet; import java.util.List; @@ -72,7 +75,7 @@ public class LauncherProvider extends ContentProvider { private static final String DATABASE_NAME = "launcher.db"; - private static final int DATABASE_VERSION = 17; + private static final int DATABASE_VERSION = 20; static final String OLD_AUTHORITY = "com.android.launcher2.settings"; static final String AUTHORITY = ProviderConfig.AUTHORITY; @@ -87,12 +90,14 @@ public class LauncherProvider extends ContentProvider { "UPGRADED_FROM_OLD_DATABASE"; static final String EMPTY_DATABASE_CREATED = "EMPTY_DATABASE_CREATED"; - static final String DEFAULT_WORKSPACE_RESOURCE_ID = - "DEFAULT_WORKSPACE_RESOURCE_ID"; private static final String ACTION_APPWIDGET_DEFAULT_WORKSPACE_CONFIGURE = "com.android.launcher.action.APPWIDGET_DEFAULT_WORKSPACE_CONFIGURE"; + private static final String URI_PARAM_IS_EXTERNAL_ADD = "isExternalAdd"; + + private LauncherProviderChangeListener mListener; + /** * {@link Uri} triggered at any registered {@link android.database.ContentObserver} when * {@link AppWidgetHost#deleteHost()} is called during database creation. @@ -116,6 +121,10 @@ public class LauncherProvider extends ContentProvider { return mOpenHelper.wasNewDbCreated(); } + public void setLauncherProviderChangeListener(LauncherProviderChangeListener listener) { + mListener = listener; + } + @Override public String getType(Uri uri) { SqlArguments args = new SqlArguments(uri, null, null); @@ -146,7 +155,7 @@ public class LauncherProvider extends ContentProvider { if (values == null) { throw new RuntimeException("Error: attempting to insert null values"); } - if (!values.containsKey(LauncherSettings.BaseLauncherColumns._ID)) { + if (!values.containsKey(LauncherSettings.ChangeLogColumns._ID)) { throw new RuntimeException("Error: attempting to add item without specifying an id"); } helper.checkId(table, values); @@ -163,6 +172,14 @@ public class LauncherProvider extends ContentProvider { public Uri insert(Uri uri, ContentValues initialValues) { SqlArguments args = new SqlArguments(uri); + // In very limited cases, we support system|signature permission apps to add to the db + String externalAdd = uri.getQueryParameter(URI_PARAM_IS_EXTERNAL_ADD); + if (externalAdd != null && "true".equals(externalAdd)) { + if (!mOpenHelper.initializeExternalAdd(initialValues)) { + return null; + } + } + SQLiteDatabase db = mOpenHelper.getWritableDatabase(); addModifiedTime(initialValues); final long rowId = dbInsertAndCheck(mOpenHelper, db, args.table, null, initialValues); @@ -174,6 +191,7 @@ public class LauncherProvider extends ContentProvider { return uri; } + @Override public int bulkInsert(Uri uri, ContentValues[] values) { SqlArguments args = new SqlArguments(uri); @@ -242,6 +260,9 @@ public class LauncherProvider extends ContentProvider { // always notify the backup agent LauncherBackupAgentHelper.dataChanged(getContext()); + if (mListener != null) { + mListener.onLauncherProviderChange(); + } } private void addModifiedTime(ContentValues values) { @@ -287,45 +308,64 @@ public class LauncherProvider extends ContentProvider { } /** - * @param workspaceResId that can be 0 to use default or non-zero for specific resource + * Clears all the data for a fresh start. */ - synchronized public void loadDefaultFavoritesIfNecessary(int origWorkspaceResId) { + synchronized public void createEmptyDB() { + mOpenHelper.createEmptyDB(mOpenHelper.getWritableDatabase()); + } + + /** + * Loads the default workspace based on the following priority scheme: + * 1) From a package provided by play store + * 2) From a partner configuration APK, already in the system image + * 3) The default configuration for the particular device + */ + synchronized public void loadDefaultFavoritesIfNecessary() { String spKey = LauncherAppState.getSharedPreferencesKey(); SharedPreferences sp = getContext().getSharedPreferences(spKey, Context.MODE_PRIVATE); if (sp.getBoolean(EMPTY_DATABASE_CREATED, false)) { Log.d(TAG, "loading default workspace"); - int workspaceResId = origWorkspaceResId; - // Use default workspace resource if none provided - if (workspaceResId == 0) { - workspaceResId = - sp.getInt(DEFAULT_WORKSPACE_RESOURCE_ID, getDefaultWorkspaceResourceId()); + WorkspaceLoader loader = AutoInstallsLayout.get(getContext(), + mOpenHelper.mAppWidgetHost, mOpenHelper); + + if (loader == null) { + final Partner partner = Partner.get(getContext().getPackageManager()); + if (partner != null && partner.hasDefaultLayout()) { + final Resources partnerRes = partner.getResources(); + int workspaceResId = partnerRes.getIdentifier(Partner.RES_DEFAULT_LAYOUT, + "xml", partner.getPackageName()); + if (workspaceResId != 0) { + loader = new SimpleWorkspaceLoader(mOpenHelper, partnerRes, workspaceResId); + } + } } - // Populate favorites table with initial favorites - SharedPreferences.Editor editor = sp.edit(); - editor.remove(EMPTY_DATABASE_CREATED); - if (origWorkspaceResId != 0) { - editor.putInt(DEFAULT_WORKSPACE_RESOURCE_ID, origWorkspaceResId); + if (loader == null) { + loader = new SimpleWorkspaceLoader(mOpenHelper, getContext().getResources(), + getDefaultWorkspaceResourceId()); } - mOpenHelper.loadFavorites(mOpenHelper.getWritableDatabase(), workspaceResId); - mOpenHelper.setFlagJustLoadedOldDb(); + // Populate favorites table with initial favorites + SharedPreferences.Editor editor = sp.edit().remove(EMPTY_DATABASE_CREATED); + mOpenHelper.loadFavorites(mOpenHelper.getWritableDatabase(), loader); editor.commit(); } } public void migrateLauncher2Shortcuts() { mOpenHelper.migrateLauncher2Shortcuts(mOpenHelper.getWritableDatabase(), - LauncherSettings.Favorites.OLD_CONTENT_URI); + Uri.parse(getContext().getString(R.string.old_launcher_provider_uri))); } private static int getDefaultWorkspaceResourceId() { + LauncherAppState app = LauncherAppState.getInstance(); + DeviceProfile grid = app.getDynamicGrid().getDeviceProfile(); if (LauncherAppState.isDisableAllApps()) { - return R.xml.default_workspace_no_all_apps; + return grid.defaultNoAllAppsLayoutId; } else { - return R.xml.default_workspace; + return grid.defaultLayoutId; } } @@ -351,18 +391,39 @@ public class LauncherProvider extends ContentProvider { mOpenHelper = new DatabaseHelper(getContext()); } - private static class DatabaseHelper extends SQLiteOpenHelper { + private static class DatabaseHelper extends SQLiteOpenHelper implements LayoutParserCallback { + private static final String TAG_RESOLVE = "resolve"; private static final String TAG_FAVORITES = "favorites"; private static final String TAG_FAVORITE = "favorite"; - private static final String TAG_CLOCK = "clock"; - private static final String TAG_SEARCH = "search"; private static final String TAG_APPWIDGET = "appwidget"; private static final String TAG_SHORTCUT = "shortcut"; private static final String TAG_FOLDER = "folder"; + private static final String TAG_PARTNER_FOLDER = "partner-folder"; private static final String TAG_EXTRA = "extra"; private static final String TAG_INCLUDE = "include"; + // Style attrs -- "Favorite" + private static final String ATTR_CLASS_NAME = "className"; + private static final String ATTR_PACKAGE_NAME = "packageName"; + private static final String ATTR_CONTAINER = "container"; + private static final String ATTR_SCREEN = "screen"; + private static final String ATTR_X = "x"; + private static final String ATTR_Y = "y"; + private static final String ATTR_SPAN_X = "spanX"; + private static final String ATTR_SPAN_Y = "spanY"; + private static final String ATTR_ICON = "icon"; + private static final String ATTR_TITLE = "title"; + private static final String ATTR_URI = "uri"; + + // Style attrs -- "Include" + private static final String ATTR_WORKSPACE = "workspace"; + + // Style attrs -- "Extra" + private static final String ATTR_KEY = "key"; + private static final String ATTR_VALUE = "value"; + private final Context mContext; + private final PackageManager mPackageManager; private final AppWidgetHost mAppWidgetHost; private long mMaxItemId = -1; private long mMaxScreenId = -1; @@ -372,6 +433,7 @@ public class LauncherProvider extends ContentProvider { DatabaseHelper(Context context) { super(context, DATABASE_NAME, null, DATABASE_VERSION); mContext = context; + mPackageManager = context.getPackageManager(); mAppWidgetHost = new AppWidgetHost(context, Launcher.APPWIDGET_HOST_ID); // In the case where neither onCreate nor onUpgrade gets called, we read the maxId from @@ -407,6 +469,10 @@ public class LauncherProvider extends ContentProvider { mMaxScreenId = 0; mNewDbCreated = true; + UserManagerCompat userManager = UserManagerCompat.getInstance(mContext); + long userSerialNumber = userManager.getSerialNumberForUser( + UserHandleCompat.myUserHandle()); + db.execSQL("CREATE TABLE favorites (" + "_id INTEGER PRIMARY KEY," + "title TEXT," + @@ -428,7 +494,8 @@ public class LauncherProvider extends ContentProvider { "displayMode INTEGER," + "appWidgetProvider TEXT," + "modified INTEGER NOT NULL DEFAULT 0," + - "restored INTEGER NOT NULL DEFAULT 0" + + "restored INTEGER NOT NULL DEFAULT 0," + + "profileId INTEGER DEFAULT " + userSerialNumber + ");"); addWorkspacesTable(db); @@ -454,7 +521,7 @@ public class LauncherProvider extends ContentProvider { "/old_favorites?notify=true"); if (!convertDatabase(db, uri, permuteScreensCb, true)) { // Try and upgrade from the Launcher2 db - uri = LauncherSettings.Favorites.OLD_CONTENT_URI; + uri = Uri.parse(mContext.getString(R.string.old_launcher_provider_uri)); if (!convertDatabase(db, uri, permuteScreensCb, false)) { // If we fail, then set a flag to load the default workspace setFlagEmptyDbCreated(); @@ -480,6 +547,37 @@ public class LauncherProvider extends ContentProvider { ");"); } + 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 " + TABLE_FAVORITES + + " WHERE " + + LauncherSettings.Favorites.SCREEN + " NOT IN (SELECT " + + LauncherSettings.WorkspaceScreens._ID + " FROM " + TABLE_WORKSPACE_SCREENS + ")" + + " 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 " + TABLE_FAVORITES + + " 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 " + TABLE_FAVORITES + + " WHERE " + LauncherSettings.Favorites.ITEM_TYPE + " = " + + LauncherSettings.Favorites.ITEM_TYPE_FOLDER + ")"; + db.execSQL(removeOrphanedFolderItems); + } + private void setFlagJustLoadedOldDb() { String spKey = LauncherAppState.getSharedPreferencesKey(); SharedPreferences sp = mContext.getSharedPreferences(spKey, Context.MODE_PRIVATE); @@ -691,7 +789,8 @@ public class LauncherProvider extends ContentProvider { } // Add default hotseat icons - loadFavorites(db, R.xml.update_workspace); + loadFavorites(db, new SimpleWorkspaceLoader(this, mContext.getResources(), + R.xml.update_workspace)); version = 9; } @@ -780,6 +879,28 @@ public class LauncherProvider extends ContentProvider { version = 17; } + if (version < 18) { + // No-op + version = 18; + } + + if (version < 19) { + // 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); + version = 19; + } + + if (version < 20) { + // Add userId column + if (addProfileColumn(db)) { + version = 20; + } + // else old version remains, which means we wipe old data + } + if (version != DATABASE_VERSION) { Log.w(TAG, "Destroying all old data."); db.execSQL("DROP TABLE IF EXISTS " + TABLE_FAVORITES); @@ -789,6 +910,47 @@ public class LauncherProvider extends ContentProvider { } } + @Override + public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) { + // This shouldn't happen -- throw our hands up in the air and start over. + Log.w(TAG, "Database version downgrade from: " + oldVersion + " to " + newVersion + + ". Wiping databse."); + createEmptyDB(db); + } + + + /** + * Clears all the data for a fresh start. + */ + public void createEmptyDB(SQLiteDatabase db) { + db.execSQL("DROP TABLE IF EXISTS " + TABLE_FAVORITES); + db.execSQL("DROP TABLE IF EXISTS " + TABLE_WORKSPACE_SCREENS); + onCreate(db); + } + + private boolean addProfileColumn(SQLiteDatabase db) { + db.beginTransaction(); + try { + UserManagerCompat userManager = UserManagerCompat.getInstance(mContext); + // Default to the serial number of this user, for older + // shortcuts. + long userSerialNumber = userManager.getSerialNumberForUser( + UserHandleCompat.myUserHandle()); + // Insert new column for holding user serial number + db.execSQL("ALTER TABLE favorites " + + "ADD COLUMN profileId INTEGER DEFAULT " + + userSerialNumber + ";"); + db.setTransactionSuccessful(); + } catch (SQLException ex) { + // Old version remains, which means we wipe old data + Log.e(TAG, ex.getMessage(), ex); + return false; + } finally { + db.endTransaction(); + } + return true; + } + private boolean updateContactsShortcuts(SQLiteDatabase db) { final String selectWhere = buildOrWhereString(Favorites.ITEM_TYPE, new int[] { Favorites.ITEM_TYPE_SHORTCUT }); @@ -930,6 +1092,7 @@ public class LauncherProvider extends ContentProvider { // constructor from the worker thread; however, this doesn't extend until after the // constructor is called, and we only pass a reference to LauncherProvider to LauncherApp // after that point + @Override public long generateNewItemId() { if (mMaxItemId < 0) { throw new RuntimeException("Error: max item id was not initialized"); @@ -938,6 +1101,11 @@ public class LauncherProvider extends ContentProvider { return mMaxItemId; } + @Override + public long insertAndCheck(SQLiteDatabase db, ContentValues values) { + return dbInsertAndCheck(this, db, TABLE_FAVORITES, null, values); + } + public void updateMaxItemId(long id) { mMaxItemId = id + 1; } @@ -1102,6 +1270,93 @@ public class LauncherProvider extends ContentProvider { if (LOGD) Log.d(TAG, "mMaxItemId: " + mMaxItemId); } + private boolean initializeExternalAdd(ContentValues values) { + // 1. Ensure that externally added items have a valid item id + long id = generateNewItemId(); + values.put(LauncherSettings.Favorites._ID, id); + + // 2. In the case of an app widget, and if no app widget id is specified, we + // attempt allocate and bind the widget. + Integer itemType = values.getAsInteger(LauncherSettings.Favorites.ITEM_TYPE); + if (itemType != null && + itemType.intValue() == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET && + !values.containsKey(LauncherSettings.Favorites.APPWIDGET_ID)) { + + final AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(mContext); + ComponentName cn = ComponentName.unflattenFromString( + values.getAsString(Favorites.APPWIDGET_PROVIDER)); + + if (cn != null) { + try { + int appWidgetId = mAppWidgetHost.allocateAppWidgetId(); + values.put(LauncherSettings.Favorites.APPWIDGET_ID, appWidgetId); + if (!appWidgetManager.bindAppWidgetIdIfAllowed(appWidgetId,cn)) { + return false; + } + } catch (RuntimeException e) { + Log.e(TAG, "Failed to initialize external widget", e); + return false; + } + } else { + return false; + } + } + + // Add screen id if not present + long screenId = values.getAsLong(LauncherSettings.Favorites.SCREEN); + if (!addScreenIdIfNecessary(screenId)) { + return false; + } + return true; + } + + // Returns true of screen id exists, or if successfully added + private boolean addScreenIdIfNecessary(long screenId) { + if (!hasScreenId(screenId)) { + int rank = getMaxScreenRank() + 1; + + ContentValues v = new ContentValues(); + v.put(LauncherSettings.WorkspaceScreens._ID, screenId); + v.put(LauncherSettings.WorkspaceScreens.SCREEN_RANK, rank); + if (dbInsertAndCheck(this, getWritableDatabase(), + TABLE_WORKSPACE_SCREENS, null, v) < 0) { + return false; + } + } + return true; + } + + private boolean hasScreenId(long screenId) { + SQLiteDatabase db = getWritableDatabase(); + Cursor c = db.rawQuery("SELECT * FROM " + TABLE_WORKSPACE_SCREENS + " WHERE " + + LauncherSettings.WorkspaceScreens._ID + " = " + screenId, null); + if (c != null) { + int count = c.getCount(); + c.close(); + return count > 0; + } else { + return false; + } + } + + private int getMaxScreenRank() { + SQLiteDatabase db = getWritableDatabase(); + Cursor c = db.rawQuery("SELECT MAX(" + LauncherSettings.WorkspaceScreens.SCREEN_RANK + + ") FROM " + TABLE_WORKSPACE_SCREENS, null); + + // get the result + final int maxRankIndex = 0; + int rank = -1; + if (c != null && c.moveToNext()) { + rank = c.getInt(maxRankIndex); + } + if (c != null) { + c.close(); + } + + return rank; + } + private static final void beginDocument(XmlPullParser parser, String firstElementName) throws XmlPullParserException, IOException { int type; @@ -1120,24 +1375,55 @@ public class LauncherProvider extends ContentProvider { } } + private static Intent buildMainIntent() { + Intent intent = new Intent(Intent.ACTION_MAIN, null); + intent.addCategory(Intent.CATEGORY_LAUNCHER); + return intent; + } + + private int loadFavorites(SQLiteDatabase db, WorkspaceLoader loader) { + ArrayList<Long> screenIds = new ArrayList<Long>(); + // TODO: Use multiple loaders with fall-back and transaction. + int count = loader.loadLayout(db, screenIds); + + // Add the screens specified by the items above + Collections.sort(screenIds); + int rank = 0; + ContentValues values = new ContentValues(); + for (Long id : screenIds) { + values.clear(); + values.put(LauncherSettings.WorkspaceScreens._ID, id); + values.put(LauncherSettings.WorkspaceScreens.SCREEN_RANK, rank); + if (dbInsertAndCheck(this, db, TABLE_WORKSPACE_SCREENS, null, values) < 0) { + throw new RuntimeException("Failed initialize screen table" + + "from default layout"); + } + rank++; + } + + // Ensure that the max ids are initialized + mMaxItemId = initializeMaxItemId(db); + mMaxScreenId = initializeMaxScreenId(db); + + return count; + } + /** * Loads the default set of favorite packages from an xml file. * * @param db The database to write the values into * @param filterContainerId The specific container id of items to load + * @param the set of screenIds which are used by the favorites */ - private int loadFavorites(SQLiteDatabase db, int workspaceResourceId) { - Intent intent = new Intent(Intent.ACTION_MAIN, null); - intent.addCategory(Intent.CATEGORY_LAUNCHER); - ContentValues values = new ContentValues(); + private int loadFavoritesRecursive(SQLiteDatabase db, Resources res, int workspaceResourceId, + ArrayList<Long> screenIds) { + ContentValues values = new ContentValues(); if (LOGD) Log.v(TAG, String.format("Loading favorites from resid=0x%08x", workspaceResourceId)); - PackageManager packageManager = mContext.getPackageManager(); - int i = 0; + int count = 0; try { - XmlResourceParser parser = mContext.getResources().getXml(workspaceResourceId); - AttributeSet attrs = Xml.asAttributeSet(parser); + XmlResourceParser parser = res.getXml(workspaceResourceId); beginDocument(parser, TAG_FAVORITES); final int depth = parser.getDepth(); @@ -1154,38 +1440,34 @@ public class LauncherProvider extends ContentProvider { final String name = parser.getName(); if (TAG_INCLUDE.equals(name)) { - final TypedArray a = mContext.obtainStyledAttributes(attrs, R.styleable.Include); - final int resId = a.getResourceId(R.styleable.Include_workspace, 0); + final int resId = getAttributeResourceValue(parser, ATTR_WORKSPACE, 0); if (LOGD) Log.v(TAG, String.format(("%" + (2*(depth+1)) + "s<include workspace=%08x>"), "", resId)); if (resId != 0 && resId != workspaceResourceId) { // recursively load some more favorites, why not? - i += loadFavorites(db, resId); + count += loadFavoritesRecursive(db, res, resId, screenIds); added = false; } else { Log.w(TAG, String.format("Skipping <include workspace=0x%08x>", resId)); } - a.recycle(); - if (LOGD) Log.v(TAG, String.format(("%" + (2*(depth+1)) + "s</include>"), "")); continue; } // Assuming it's a <favorite> at this point - TypedArray a = mContext.obtainStyledAttributes(attrs, R.styleable.Favorite); - long container = LauncherSettings.Favorites.CONTAINER_DESKTOP; - if (a.hasValue(R.styleable.Favorite_container)) { - container = Long.valueOf(a.getString(R.styleable.Favorite_container)); + String strContainer = getAttributeValue(parser, ATTR_CONTAINER); + if (strContainer != null) { + container = Long.valueOf(strContainer); } - String screen = a.getString(R.styleable.Favorite_screen); - String x = a.getString(R.styleable.Favorite_x); - String y = a.getString(R.styleable.Favorite_y); + String screen = getAttributeValue(parser, ATTR_SCREEN); + String x = getAttributeValue(parser, ATTR_X); + String y = getAttributeValue(parser, ATTR_Y); values.clear(); values.put(LauncherSettings.Favorites.CONTAINER, container); @@ -1194,8 +1476,8 @@ public class LauncherProvider extends ContentProvider { values.put(LauncherSettings.Favorites.CELLY, y); if (LOGD) { - final String title = a.getString(R.styleable.Favorite_title); - final String pkg = a.getString(R.styleable.Favorite_packageName); + final String title = getAttributeValue(parser, ATTR_TITLE); + final String pkg = getAttributeValue(parser, ATTR_PACKAGE_NAME); final String something = title != null ? title : pkg; Log.v(TAG, String.format( ("%" + (2*(depth+1)) + "s<%s%s c=%d s=%s x=%s y=%s>"), @@ -1205,82 +1487,62 @@ public class LauncherProvider extends ContentProvider { } if (TAG_FAVORITE.equals(name)) { - long id = addAppShortcut(db, values, a, packageManager, intent); + long id = addAppShortcut(db, values, parser); added = id >= 0; - } else if (TAG_SEARCH.equals(name)) { - added = addSearchWidget(db, values); - } else if (TAG_CLOCK.equals(name)) { - added = addClockWidget(db, values); } else if (TAG_APPWIDGET.equals(name)) { - added = addAppWidget(parser, attrs, type, db, values, a, packageManager); + added = addAppWidget(parser, type, db, values); } else if (TAG_SHORTCUT.equals(name)) { - long id = addUriShortcut(db, values, a); + long id = addUriShortcut(db, values, res, parser); added = id >= 0; - } else if (TAG_FOLDER.equals(name)) { - String title; - int titleResId = a.getResourceId(R.styleable.Favorite_title, -1); - if (titleResId != -1) { - title = mContext.getResources().getString(titleResId); - } else { - title = mContext.getResources().getString(R.string.folder_name); - } - values.put(LauncherSettings.Favorites.TITLE, title); - long folderId = addFolder(db, values); - added = folderId >= 0; - - ArrayList<Long> folderItems = new ArrayList<Long>(); - - int folderDepth = parser.getDepth(); + } else if (TAG_RESOLVE.equals(name)) { + // This looks through the contained favorites (or meta-favorites) and + // attempts to add them as shortcuts in the fallback group's location + // until one is added successfully. + added = false; + final int groupDepth = parser.getDepth(); while ((type = parser.next()) != XmlPullParser.END_TAG || - parser.getDepth() > folderDepth) { + parser.getDepth() > groupDepth) { if (type != XmlPullParser.START_TAG) { continue; } - final String folder_item_name = parser.getName(); - - TypedArray ar = mContext.obtainStyledAttributes(attrs, - R.styleable.Favorite); - values.clear(); - values.put(LauncherSettings.Favorites.CONTAINER, folderId); - - if (LOGD) { - final String pkg = ar.getString(R.styleable.Favorite_packageName); - final String uri = ar.getString(R.styleable.Favorite_uri); - Log.v(TAG, String.format(("%" + (2*(folderDepth+1)) + "s<%s \"%s\">"), "", - folder_item_name, uri != null ? uri : pkg)); - } - - if (TAG_FAVORITE.equals(folder_item_name) && folderId >= 0) { - long id = - addAppShortcut(db, values, ar, packageManager, intent); - if (id >= 0) { - folderItems.add(id); + final String fallback_item_name = parser.getName(); + if (!added) { + if (TAG_FAVORITE.equals(fallback_item_name)) { + final long id = addAppShortcut(db, values, parser); + added = id >= 0; + } else { + Log.e(TAG, "Fallback groups can contain only favorites, found " + + fallback_item_name); } - } else if (TAG_SHORTCUT.equals(folder_item_name) && folderId >= 0) { - long id = addUriShortcut(db, values, ar); - if (id >= 0) { - folderItems.add(id); - } - } else { - throw new RuntimeException("Folders can " + - "contain only shortcuts"); } - ar.recycle(); } - // We can only have folders with >= 2 items, so we need to remove the - // folder and clean up if less than 2 items were included, or some - // failed to add, and less than 2 were actually added - if (folderItems.size() < 2 && folderId >= 0) { - // We just delete the folder and any items that made it - deleteId(db, folderId); - if (folderItems.size() > 0) { - deleteId(db, folderItems.get(0)); + } else if (TAG_FOLDER.equals(name)) { + // Folder contents are nested in this XML file + added = loadFolder(db, values, res, parser); + + } else if (TAG_PARTNER_FOLDER.equals(name)) { + // Folder contents come from an external XML resource + final Partner partner = Partner.get(mPackageManager); + if (partner != null) { + final Resources partnerRes = partner.getResources(); + final int resId = partnerRes.getIdentifier(Partner.RES_FOLDER, + "xml", partner.getPackageName()); + if (resId != 0) { + final XmlResourceParser partnerParser = partnerRes.getXml(resId); + beginDocument(partnerParser, TAG_FOLDER); + added = loadFolder(db, values, partnerRes, partnerParser); } - added = false; } } - if (added) i++; - a.recycle(); + if (added) { + long screenId = Long.parseLong(screen); + // Keep track of the set of screens which need to be added to the db. + if (!screenIds.contains(screenId) && + container == LauncherSettings.Favorites.CONTAINER_DESKTOP) { + screenIds.add(screenId); + } + count++; + } } } catch (XmlPullParserException e) { Log.w(TAG, "Got exception parsing favorites.", e); @@ -1289,50 +1551,231 @@ public class LauncherProvider extends ContentProvider { } catch (RuntimeException e) { Log.w(TAG, "Got exception parsing favorites.", e); } + return count; + } - // Update the max item id after we have loaded the database - if (mMaxItemId == -1) { - mMaxItemId = initializeMaxItemId(db); + /** + * Parse folder items starting at {@link XmlPullParser} location. Allow recursive + * includes of items. + */ + private void addToFolder(SQLiteDatabase db, Resources res, XmlResourceParser parser, + ArrayList<Long> folderItems, long folderId) throws IOException, XmlPullParserException { + int type; + int folderDepth = parser.getDepth(); + while ((type = parser.next()) != XmlPullParser.END_TAG || + parser.getDepth() > folderDepth) { + if (type != XmlPullParser.START_TAG) { + continue; + } + final String tag = parser.getName(); + + final ContentValues childValues = new ContentValues(); + childValues.put(LauncherSettings.Favorites.CONTAINER, folderId); + + if (LOGD) { + final String pkg = getAttributeValue(parser, ATTR_PACKAGE_NAME); + final String uri = getAttributeValue(parser, ATTR_URI); + Log.v(TAG, String.format(("%" + (2*(folderDepth+1)) + "s<%s \"%s\">"), "", + tag, uri != null ? uri : pkg)); + } + + if (TAG_FAVORITE.equals(tag) && folderId >= 0) { + final long id = addAppShortcut(db, childValues, parser); + if (id >= 0) { + folderItems.add(id); + } + } else if (TAG_SHORTCUT.equals(tag) && folderId >= 0) { + final long id = addUriShortcut(db, childValues, res, parser); + if (id >= 0) { + folderItems.add(id); + } + } else if (TAG_INCLUDE.equals(tag) && folderId >= 0) { + addToFolder(db, res, parser, folderItems, folderId); + } else { + throw new RuntimeException("Folders can contain only shortcuts"); + } } + } - return i; + /** + * Parse folder starting at current {@link XmlPullParser} location. + */ + private boolean loadFolder(SQLiteDatabase db, ContentValues values, Resources res, + XmlResourceParser parser) throws IOException, XmlPullParserException { + final String title; + final int titleResId = getAttributeResourceValue(parser, ATTR_TITLE, 0); + if (titleResId != 0) { + title = res.getString(titleResId); + } else { + title = mContext.getResources().getString(R.string.folder_name); + } + + values.put(LauncherSettings.Favorites.TITLE, title); + long folderId = addFolder(db, values); + boolean added = folderId >= 0; + + ArrayList<Long> folderItems = new ArrayList<Long>(); + addToFolder(db, res, parser, folderItems, folderId); + + // We can only have folders with >= 2 items, so we need to remove the + // folder and clean up if less than 2 items were included, or some + // failed to add, and less than 2 were actually added + if (folderItems.size() < 2 && folderId >= 0) { + // Delete the folder + deleteId(db, folderId); + + // If we have a single item, promote it to where the folder + // would have been. + if (folderItems.size() == 1) { + final ContentValues childValues = new ContentValues(); + copyInteger(values, childValues, LauncherSettings.Favorites.CONTAINER); + copyInteger(values, childValues, LauncherSettings.Favorites.SCREEN); + copyInteger(values, childValues, LauncherSettings.Favorites.CELLX); + copyInteger(values, childValues, LauncherSettings.Favorites.CELLY); + + final long id = folderItems.get(0); + db.update(TABLE_FAVORITES, childValues, + LauncherSettings.Favorites._ID + "=" + id, null); + } else { + added = false; + } + } + return added; } - private long addAppShortcut(SQLiteDatabase db, ContentValues values, TypedArray a, - PackageManager packageManager, Intent intent) { - long id = -1; - ActivityInfo info; - String packageName = a.getString(R.styleable.Favorite_packageName); - String className = a.getString(R.styleable.Favorite_className); + // A meta shortcut attempts to resolve an intent specified as a URI in the XML, if a + // logical choice for what shortcut should be used for that intent exists, then it is + // added. Otherwise add nothing. + private long addAppShortcutByUri(SQLiteDatabase db, ContentValues values, + String intentUri) { + Intent metaIntent; try { - ComponentName cn; + metaIntent = Intent.parseUri(intentUri, 0); + } catch (URISyntaxException e) { + Log.e(TAG, "Unable to add meta-favorite: " + intentUri, e); + return -1; + } + + ResolveInfo resolved = mPackageManager.resolveActivity(metaIntent, + PackageManager.MATCH_DEFAULT_ONLY); + final List<ResolveInfo> appList = mPackageManager.queryIntentActivities( + metaIntent, PackageManager.MATCH_DEFAULT_ONLY); + + // Verify that the result is an app and not just the resolver dialog asking which + // app to use. + if (wouldLaunchResolverActivity(resolved, appList)) { + // If only one of the results is a system app then choose that as the default. + final ResolveInfo systemApp = getSingleSystemActivity(appList); + if (systemApp == null) { + // There is no logical choice for this meta-favorite, so rather than making + // a bad choice just add nothing. + Log.w(TAG, "No preference or single system activity found for " + + metaIntent.toString()); + return -1; + } + resolved = systemApp; + } + final ActivityInfo info = resolved.activityInfo; + final Intent intent = mPackageManager.getLaunchIntentForPackage(info.packageName); + if (intent == null) { + return -1; + } + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | + Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); + + return addAppShortcut(db, values, info.loadLabel(mPackageManager).toString(), intent); + } + + private ResolveInfo getSingleSystemActivity(List<ResolveInfo> appList) { + ResolveInfo systemResolve = null; + final int N = appList.size(); + for (int i = 0; i < N; ++i) { try { - cn = new ComponentName(packageName, className); - info = packageManager.getActivityInfo(cn, 0); - } catch (PackageManager.NameNotFoundException nnfe) { - String[] packages = packageManager.currentToCanonicalPackageNames( - new String[] { packageName }); - cn = new ComponentName(packages[0], className); - info = packageManager.getActivityInfo(cn, 0); + ApplicationInfo info = mPackageManager.getApplicationInfo( + appList.get(i).activityInfo.packageName, 0); + if ((info.flags & ApplicationInfo.FLAG_SYSTEM) != 0) { + if (systemResolve != null) { + return null; + } else { + systemResolve = appList.get(i); + } + } + } catch (PackageManager.NameNotFoundException e) { + Log.w(TAG, "Unable to get info about resolve results", e); + return null; } - id = generateNewItemId(); - intent.setComponent(cn); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | - Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); - values.put(Favorites.INTENT, intent.toUri(0)); - values.put(Favorites.TITLE, info.loadLabel(packageManager).toString()); - values.put(Favorites.ITEM_TYPE, Favorites.ITEM_TYPE_APPLICATION); - values.put(Favorites.SPANX, 1); - values.put(Favorites.SPANY, 1); - values.put(Favorites._ID, generateNewItemId()); - if (dbInsertAndCheck(this, db, TABLE_FAVORITES, null, values) < 0) { - return -1; + } + return systemResolve; + } + + private boolean wouldLaunchResolverActivity(ResolveInfo resolved, + List<ResolveInfo> appList) { + // If the list contains the above resolved activity, then it can't be + // ResolverActivity itself. + for (int i = 0; i < appList.size(); ++i) { + ResolveInfo tmp = appList.get(i); + if (tmp.activityInfo.name.equals(resolved.activityInfo.name) + && tmp.activityInfo.packageName.equals(resolved.activityInfo.packageName)) { + return false; } - } catch (PackageManager.NameNotFoundException e) { - Log.w(TAG, "Unable to add favorite: " + packageName + - "/" + className, e); } - return id; + return true; + } + + private long addAppShortcut(SQLiteDatabase db, ContentValues values, + XmlResourceParser parser) { + final String packageName = getAttributeValue(parser, ATTR_PACKAGE_NAME); + final String className = getAttributeValue(parser, ATTR_CLASS_NAME); + final String uri = getAttributeValue(parser, ATTR_URI); + + if (!TextUtils.isEmpty(packageName) && !TextUtils.isEmpty(className)) { + ActivityInfo info; + try { + ComponentName cn; + try { + cn = new ComponentName(packageName, className); + info = mPackageManager.getActivityInfo(cn, 0); + } catch (PackageManager.NameNotFoundException nnfe) { + String[] packages = mPackageManager.currentToCanonicalPackageNames( + new String[] { packageName }); + cn = new ComponentName(packages[0], className); + info = mPackageManager.getActivityInfo(cn, 0); + } + final Intent intent = buildMainIntent(); + intent.setComponent(cn); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | + Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); + + return addAppShortcut(db, values, info.loadLabel(mPackageManager).toString(), + intent); + } catch (PackageManager.NameNotFoundException e) { + Log.w(TAG, "Unable to add favorite: " + packageName + + "/" + className, e); + } + return -1; + } else if (!TextUtils.isEmpty(uri)) { + // If no component specified try to find a shortcut to add from the URI. + return addAppShortcutByUri(db, values, uri); + } else { + Log.e(TAG, "Skipping invalid <favorite> with no component or uri"); + return -1; + } + } + + private long addAppShortcut(SQLiteDatabase db, ContentValues values, String title, + Intent intent) { + long id = generateNewItemId(); + values.put(Favorites.INTENT, intent.toUri(0)); + values.put(Favorites.TITLE, title); + values.put(Favorites.ITEM_TYPE, Favorites.ITEM_TYPE_APPLICATION); + values.put(Favorites.SPANX, 1); + values.put(Favorites.SPANY, 1); + values.put(Favorites._ID, id); + if (dbInsertAndCheck(this, db, TABLE_FAVORITES, null, values) < 0) { + return -1; + } else { + return id; + } } private long addFolder(SQLiteDatabase db, ContentValues values) { @@ -1374,23 +1817,12 @@ public class LauncherProvider extends ContentProvider { return null; } - private boolean addSearchWidget(SQLiteDatabase db, ContentValues values) { - ComponentName cn = getSearchWidgetProvider(); - return addAppWidget(db, values, cn, 4, 1, null); - } - - private boolean addClockWidget(SQLiteDatabase db, ContentValues values) { - ComponentName cn = new ComponentName("com.android.alarmclock", - "com.android.alarmclock.AnalogAppWidgetProvider"); - return addAppWidget(db, values, cn, 2, 2, null); - } - - private boolean addAppWidget(XmlResourceParser parser, AttributeSet attrs, int type, - SQLiteDatabase db, ContentValues values, TypedArray a, - PackageManager packageManager) throws XmlPullParserException, IOException { + private boolean addAppWidget(XmlResourceParser parser, int type, + SQLiteDatabase db, ContentValues values) + throws XmlPullParserException, IOException { - String packageName = a.getString(R.styleable.Favorite_packageName); - String className = a.getString(R.styleable.Favorite_className); + String packageName = getAttributeValue(parser, ATTR_PACKAGE_NAME); + String className = getAttributeValue(parser, ATTR_CLASS_NAME); if (packageName == null || className == null) { return false; @@ -1399,21 +1831,25 @@ public class LauncherProvider extends ContentProvider { boolean hasPackage = true; ComponentName cn = new ComponentName(packageName, className); try { - packageManager.getReceiverInfo(cn, 0); + mPackageManager.getReceiverInfo(cn, 0); } catch (Exception e) { - String[] packages = packageManager.currentToCanonicalPackageNames( + String[] packages = mPackageManager.currentToCanonicalPackageNames( new String[] { packageName }); cn = new ComponentName(packages[0], className); try { - packageManager.getReceiverInfo(cn, 0); + mPackageManager.getReceiverInfo(cn, 0); } catch (Exception e1) { + System.out.println("Can't find widget provider: " + className); hasPackage = false; } } if (hasPackage) { - int spanX = a.getInt(R.styleable.Favorite_spanX, 0); - int spanY = a.getInt(R.styleable.Favorite_spanY, 0); + String spanX = getAttributeValue(parser, ATTR_SPAN_X); + String spanY = getAttributeValue(parser, ATTR_SPAN_Y); + + values.put(Favorites.SPANX, spanX); + values.put(Favorites.SPANY, spanY); // Read the extras Bundle extras = new Bundle(); @@ -1424,10 +1860,9 @@ public class LauncherProvider extends ContentProvider { continue; } - TypedArray ar = mContext.obtainStyledAttributes(attrs, R.styleable.Extra); if (TAG_EXTRA.equals(parser.getName())) { - String key = ar.getString(R.styleable.Extra_key); - String value = ar.getString(R.styleable.Extra_value); + String key = getAttributeValue(parser, ATTR_KEY); + String value = getAttributeValue(parser, ATTR_VALUE); if (key != null && value != null) { extras.putString(key, value); } else { @@ -1436,16 +1871,16 @@ public class LauncherProvider extends ContentProvider { } else { throw new RuntimeException("Widgets can contain only extras"); } - ar.recycle(); } - return addAppWidget(db, values, cn, spanX, spanY, extras); + return addAppWidget(db, values, cn, extras); } return false; } + private boolean addAppWidget(SQLiteDatabase db, ContentValues values, ComponentName cn, - int spanX, int spanY, Bundle extras) { + Bundle extras) { boolean allocatedAppWidgets = false; final AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(mContext); @@ -1453,8 +1888,6 @@ public class LauncherProvider extends ContentProvider { int appWidgetId = mAppWidgetHost.allocateAppWidgetId(); values.put(Favorites.ITEM_TYPE, Favorites.ITEM_TYPE_APPWIDGET); - values.put(Favorites.SPANX, spanX); - values.put(Favorites.SPANY, spanY); values.put(Favorites.APPWIDGET_ID, appWidgetId); values.put(Favorites.APPWIDGET_PROVIDER, cn.flattenToString()); values.put(Favorites._ID, generateNewItemId()); @@ -1480,17 +1913,15 @@ public class LauncherProvider extends ContentProvider { return allocatedAppWidgets; } - private long addUriShortcut(SQLiteDatabase db, ContentValues values, - TypedArray a) { - Resources r = mContext.getResources(); - - final int iconResId = a.getResourceId(R.styleable.Favorite_icon, 0); - final int titleResId = a.getResourceId(R.styleable.Favorite_title, 0); + private long addUriShortcut(SQLiteDatabase db, ContentValues values, Resources res, + XmlResourceParser parser) { + final int iconResId = getAttributeResourceValue(parser, ATTR_ICON, 0); + final int titleResId = getAttributeResourceValue(parser, ATTR_TITLE, 0); Intent intent; String uri = null; try { - uri = a.getString(R.styleable.Favorite_uri); + uri = getAttributeValue(parser, ATTR_URI); intent = Intent.parseUri(uri, 0); } catch (URISyntaxException e) { Log.w(TAG, "Shortcut has malformed uri: " + uri); @@ -1505,13 +1936,13 @@ public class LauncherProvider extends ContentProvider { long id = generateNewItemId(); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); values.put(Favorites.INTENT, intent.toUri(0)); - values.put(Favorites.TITLE, r.getString(titleResId)); + values.put(Favorites.TITLE, res.getString(titleResId)); values.put(Favorites.ITEM_TYPE, Favorites.ITEM_TYPE_SHORTCUT); values.put(Favorites.SPANX, 1); values.put(Favorites.SPANY, 1); values.put(Favorites.ICON_TYPE, Favorites.ICON_TYPE_RESOURCE); - values.put(Favorites.ICON_PACKAGE, mContext.getPackageName()); - values.put(Favorites.ICON_RESOURCE, r.getResourceName(iconResId)); + values.put(Favorites.ICON_PACKAGE, res.getResourcePackageName(iconResId)); + values.put(Favorites.ICON_RESOURCE, res.getResourceName(iconResId)); values.put(Favorites._ID, id); if (dbInsertAndCheck(this, db, TABLE_FAVORITES, null, values) < 0) { @@ -1520,7 +1951,7 @@ public class LauncherProvider extends ContentProvider { return id; } - public void migrateLauncher2Shortcuts(SQLiteDatabase db, Uri uri) { + private void migrateLauncher2Shortcuts(SQLiteDatabase db, Uri uri) { final ContentResolver resolver = mContext.getContentResolver(); Cursor c = null; int count = 0; @@ -1563,6 +1994,8 @@ public class LauncherProvider extends ContentProvider { = c.getColumnIndexOrThrow(LauncherSettings.Favorites.URI); final int displayModeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.DISPLAY_MODE); + final int profileIndex + = c.getColumnIndex(LauncherSettings.Favorites.PROFILE_ID); int i = 0; int curX = 0; @@ -1573,7 +2006,6 @@ public class LauncherProvider extends ContentProvider { final int width = (int) grid.numColumns; final int height = (int) grid.numRows; final int hotseatWidth = (int) grid.numHotseatIcons; - PackageManager pm = mContext.getPackageManager(); final HashSet<String> seenIntents = new HashSet<String>(c.getCount()); @@ -1594,6 +2026,19 @@ public class LauncherProvider extends ContentProvider { final int screen = c.getInt(screenIndex); int container = c.getInt(containerIndex); final String intentStr = c.getString(intentIndex); + + UserManagerCompat userManager = UserManagerCompat.getInstance(mContext); + UserHandleCompat userHandle; + final long userSerialNumber; + if (profileIndex != -1 && !c.isNull(profileIndex)) { + userSerialNumber = c.getInt(profileIndex); + userHandle = userManager.getUserForSerialNumber(userSerialNumber); + } else { + // Default to the serial number of this user, for older + // shortcuts. + userHandle = UserHandleCompat.myUserHandle(); + userSerialNumber = userManager.getSerialNumberForUser(userHandle); + } Launcher.addDumpLog(TAG, "migrating \"" + c.getString(titleIndex) + "\" (" + cellX + "," + cellY + "@" @@ -1620,7 +2065,8 @@ public class LauncherProvider extends ContentProvider { Launcher.addDumpLog(TAG, "skipping empty intent", true); continue; } else if (cn != null && - !LauncherModel.isValidPackageComponent(pm, cn)) { + !LauncherModel.isValidPackageActivity(mContext, cn, + userHandle)) { // component no longer exists. Launcher.addDumpLog(TAG, "skipping item whose component " + "no longer exists.", true); @@ -1659,6 +2105,7 @@ public class LauncherProvider extends ContentProvider { values.put(LauncherSettings.Favorites.URI, c.getString(uriIndex)); values.put(LauncherSettings.Favorites.DISPLAY_MODE, c.getInt(displayModeIndex)); + values.put(LauncherSettings.Favorites.PROFILE_ID, userSerialNumber); if (container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) { hotseat.put(screen, values); @@ -1792,7 +2239,7 @@ public class LauncherProvider extends ContentProvider { * Build a query string that will match any row where the column matches * anything in the values list. */ - static String buildOrWhereString(String column, int[] values) { + private static String buildOrWhereString(String column, int[] values) { StringBuilder selectWhere = new StringBuilder(); for (int i = values.length - 1; i >= 0; i--) { selectWhere.append(column).append("=").append(values[i]); @@ -1803,6 +2250,38 @@ public class LauncherProvider extends ContentProvider { return selectWhere.toString(); } + /** + * Return attribute value, attempting launcher-specific namespace first + * before falling back to anonymous attribute. + */ + private static String getAttributeValue(XmlResourceParser parser, String attribute) { + String value = parser.getAttributeValue( + "http://schemas.android.com/apk/res-auto/com.android.launcher3", attribute); + if (value == null) { + value = parser.getAttributeValue(null, attribute); + } + return value; + } + + /** + * Return attribute resource value, attempting launcher-specific namespace + * first before falling back to anonymous attribute. + */ + private static int getAttributeResourceValue(XmlResourceParser parser, String attribute, + int defaultValue) { + int value = parser.getAttributeResourceValue( + "http://schemas.android.com/apk/res-auto/com.android.launcher3", attribute, + defaultValue); + if (value == defaultValue) { + value = parser.getAttributeResourceValue(null, attribute, defaultValue); + } + return value; + } + + private static void copyInteger(ContentValues from, ContentValues to, String key) { + to.put(key, from.getAsInteger(key)); + } + static class SqlArguments { public final String table; public final String where; @@ -1834,4 +2313,29 @@ public class LauncherProvider extends ContentProvider { } } } + + static interface WorkspaceLoader { + /** + * @param screenIds A mutable list of screen its + * @return the number of workspace items added. + */ + int loadLayout(SQLiteDatabase db, ArrayList<Long> screenIds); + } + + private static class SimpleWorkspaceLoader implements WorkspaceLoader { + private final Resources mRes; + private final int mWorkspaceId; + private final DatabaseHelper mHelper; + + SimpleWorkspaceLoader(DatabaseHelper helper, Resources res, int workspaceId) { + mHelper = helper; + mRes = res; + mWorkspaceId = workspaceId; + } + + @Override + public int loadLayout(SQLiteDatabase db, ArrayList<Long> screenIds) { + return mHelper.loadFavoritesRecursive(db, mRes, mWorkspaceId, screenIds); + } + } } diff --git a/src/com/android/launcher3/LauncherProviderChangeListener.java b/src/com/android/launcher3/LauncherProviderChangeListener.java new file mode 100644 index 000000000..0de96fbc4 --- /dev/null +++ b/src/com/android/launcher3/LauncherProviderChangeListener.java @@ -0,0 +1,11 @@ +package com.android.launcher3; + +/** + * This class is a listener for {@link LauncherProvider} changes. It gets notified in the + * sendNotify method. This listener is needed because by default the Launcher suppresses + * standard data change callbacks. + */ +public interface LauncherProviderChangeListener { + + public void onLauncherProviderChange(); +} diff --git a/src/com/android/launcher3/LauncherSettings.java b/src/com/android/launcher3/LauncherSettings.java index 2a768a278..355370283 100644 --- a/src/com/android/launcher3/LauncherSettings.java +++ b/src/com/android/launcher3/LauncherSettings.java @@ -212,6 +212,14 @@ class LauncherSettings { static final String SPANY = "spanY"; /** + * The profile id of the item in the cell. + * <P> + * Type: INTEGER + * </P> + */ + static final String PROFILE_ID = "profileId"; + + /** * The favorite is a user created folder */ static final int ITEM_TYPE_FOLDER = 2; diff --git a/src/com/android/launcher3/LogAccelerateInterpolator.java b/src/com/android/launcher3/LogAccelerateInterpolator.java new file mode 100644 index 000000000..c3bbfa536 --- /dev/null +++ b/src/com/android/launcher3/LogAccelerateInterpolator.java @@ -0,0 +1,25 @@ +package com.android.launcher3; + +import android.animation.TimeInterpolator; + +public class LogAccelerateInterpolator implements TimeInterpolator { + + int mBase; + int mDrift; + final float mLogScale; + + public LogAccelerateInterpolator(int base, int drift) { + mBase = base; + mDrift = drift; + mLogScale = 1f / computeLog(1, mBase, mDrift); + } + + static float computeLog(float t, int base, int drift) { + return (float) -Math.pow(base, -t) + 1 + (drift * t); + } + + @Override + public float getInterpolation(float t) { + return 1 - computeLog(1 - t, mBase, mDrift) * mLogScale; + } +} diff --git a/src/com/android/launcher3/LogDecelerateInterpolator.java b/src/com/android/launcher3/LogDecelerateInterpolator.java new file mode 100644 index 000000000..4c5f6f08c --- /dev/null +++ b/src/com/android/launcher3/LogDecelerateInterpolator.java @@ -0,0 +1,26 @@ +package com.android.launcher3; + +import android.animation.TimeInterpolator; + +public class LogDecelerateInterpolator implements TimeInterpolator { + + int mBase; + int mDrift; + final float mLogScale; + + public LogDecelerateInterpolator(int base, int drift) { + mBase = base; + mDrift = drift; + + mLogScale = 1f / computeLog(1, mBase, mDrift); + } + + static float computeLog(float t, int base, int drift) { + return (float) -Math.pow(base, -t) + 1 + (drift * t); + } + + @Override + public float getInterpolation(float t) { + return computeLog(t, mBase, mDrift) * mLogScale; + } +} diff --git a/src/com/android/launcher3/MainThreadExecutor.java b/src/com/android/launcher3/MainThreadExecutor.java new file mode 100644 index 000000000..866b17c71 --- /dev/null +++ b/src/com/android/launcher3/MainThreadExecutor.java @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2014 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.Handler; +import android.os.Looper; + +import java.util.List; +import java.util.concurrent.AbstractExecutorService; +import java.util.concurrent.TimeUnit; + +/** + * An executor service that executes its tasks on the main thread. + * + * Shutting down this executor is not supported. + */ +public class MainThreadExecutor extends AbstractExecutorService { + + private Handler mHandler = new Handler(Looper.getMainLooper()); + + @Override + public void execute(Runnable runnable) { + if (Looper.getMainLooper() == Looper.myLooper()) { + runnable.run(); + } else { + mHandler.post(runnable); + } + } + + /** + * Not supported and throws an exception when used. + */ + @Override + @Deprecated + public void shutdown() { + throw new UnsupportedOperationException(); + } + + /** + * Not supported and throws an exception when used. + */ + @Override + @Deprecated + public List<Runnable> shutdownNow() { + throw new UnsupportedOperationException(); + } + + @Override + public boolean isShutdown() { + return false; + } + + @Override + public boolean isTerminated() { + return false; + } + + /** + * Not supported and throws an exception when used. + */ + @Override + @Deprecated + public boolean awaitTermination(long l, TimeUnit timeUnit) throws InterruptedException { + throw new UnsupportedOperationException(); + } +} diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java index 8d5d8dd4d..48fc0c98f 100644 --- a/src/com/android/launcher3/PagedView.java +++ b/src/com/android/launcher3/PagedView.java @@ -74,11 +74,12 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc private static final int MIN_LENGTH_FOR_FLING = 25; protected static final int PAGE_SNAP_ANIMATION_DURATION = 750; + protected static final int OVER_SCROLL_PAGE_SNAP_ANIMATION_DURATION = 350; protected static final int SLOW_PAGE_SNAP_ANIMATION_DURATION = 950; protected static final float NANOTIME_DIV = 1000000000.0f; private static final float OVERSCROLL_ACCELERATE_FACTOR = 2; - private static final float OVERSCROLL_DAMP_FACTOR = 0.14f; + private static final float OVERSCROLL_DAMP_FACTOR = 0.07f; private static final float RETURN_TO_ORIGINAL_PAGE_THRESHOLD = 0.33f; // The page is moved more than halfway, automatically move to the next page on touch up. @@ -152,16 +153,11 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc protected int mTouchState = TOUCH_STATE_REST; protected boolean mForceScreenScrolled = false; - protected OnLongClickListener mLongClickListener; protected int mTouchSlop; private int mPagingTouchSlop; private int mMaximumVelocity; - protected int mPageLayoutPaddingTop; - protected int mPageLayoutPaddingBottom; - protected int mPageLayoutPaddingLeft; - protected int mPageLayoutPaddingRight; protected int mPageLayoutWidthGap; protected int mPageLayoutHeightGap; protected int mCellCountX = 0; @@ -171,6 +167,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc protected int mUnboundedScrollX; protected int[] mTempVisiblePagesRange = new int[2]; protected boolean mForceDrawAllChildrenNextFrame; + private boolean mSpacePagesAutomatically = false; // mOverScrollX is equal to getScrollX() when we're within the normal scroll range. Otherwise // it is equal to the scaled overscroll position. We use a separate value so as to prevent @@ -283,14 +280,6 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.PagedView, defStyle, 0); - mPageLayoutPaddingTop = a.getDimensionPixelSize( - R.styleable.PagedView_pageLayoutPaddingTop, 0); - mPageLayoutPaddingBottom = a.getDimensionPixelSize( - R.styleable.PagedView_pageLayoutPaddingBottom, 0); - mPageLayoutPaddingLeft = a.getDimensionPixelSize( - R.styleable.PagedView_pageLayoutPaddingLeft, 0); - mPageLayoutPaddingRight = a.getDimensionPixelSize( - R.styleable.PagedView_pageLayoutPaddingRight, 0); mPageLayoutWidthGap = a.getDimensionPixelSize( R.styleable.PagedView_pageLayoutWidthGap, 0); mPageLayoutHeightGap = a.getDimensionPixelSize( @@ -339,8 +328,9 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc // Hook up the page indicator ViewGroup parent = (ViewGroup) getParent(); + ViewGroup grandParent = (ViewGroup) parent.getParent(); if (mPageIndicator == null && mPageIndicatorViewId > -1) { - mPageIndicator = (PageIndicator) parent.findViewById(mPageIndicatorViewId); + mPageIndicator = (PageIndicator) grandParent.findViewById(mPageIndicatorViewId); mPageIndicator.removeAllMarkers(mAllowPagedViewAnimations); ArrayList<PageIndicator.PageMarkerResources> markers = @@ -547,6 +537,19 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc mNextPage = INVALID_PAGE; } + private int validateNewPage(int newPage) { + int validatedPage = newPage; + // When in free scroll mode, we need to clamp to the free scroll page range. + if (mFreeScroll) { + getFreeScrollPageRange(mTempVisiblePagesRange); + validatedPage = Math.max(mTempVisiblePagesRange[0], + Math.min(newPage, mTempVisiblePagesRange[1])); + } + // Ensure that it is clamped by the actual set of children in all cases + validatedPage = Math.max(0, Math.min(validatedPage, getPageCount() - 1)); + return validatedPage; + } + /** * Sets the current page. */ @@ -560,7 +563,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc return; } mForceScreenScrolled = true; - mCurrentPage = Math.max(0, Math.min(currentPage, getPageCount() - 1)); + mCurrentPage = validateNewPage(currentPage); updateCurrentPageScroll(); notifyPageSwitchListener(); invalidate(); @@ -591,8 +594,11 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc private void updatePageIndicator() { // Update the page indicator (when we aren't reordering) - if (mPageIndicator != null && !isReordering(false)) { - mPageIndicator.setActiveMarker(getNextPage()); + if (mPageIndicator != null) { + mPageIndicator.setContentDescription(getPageIndicatorDescription()); + if (!isReordering(false)) { + mPageIndicator.setActiveMarker(getNextPage()); + } } } protected void pageBeginMoving() { @@ -727,7 +733,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc } else if (mNextPage != INVALID_PAGE) { sendScrollAccessibilityEvent(); - mCurrentPage = Math.max(0, Math.min(mNextPage, getPageCount() - 1)); + mCurrentPage = validateNewPage(mNextPage); mNextPage = INVALID_PAGE; notifyPageSwitchListener(); @@ -843,6 +849,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc final int verticalPadding = getPaddingTop() + getPaddingBottom(); final int horizontalPadding = getPaddingLeft() + getPaddingRight(); + int referenceChildWidth = 0; // The children are given the same width and height as the workspace // unless they were set to WRAP_CONTENT if (DEBUG) Log.d(TAG, "PagedView.onMeasure(): " + widthSize + ", " + heightSize); @@ -887,6 +894,9 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc childWidth = getViewportWidth() - mInsets.left - mInsets.right; childHeight = getViewportHeight(); } + if (referenceChildWidth == 0) { + referenceChildWidth = childWidth; + } final int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(childWidth, childWidthMode); @@ -895,9 +905,24 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc child.measure(childWidthMeasureSpec, childHeightMeasureSpec); } } + if (mSpacePagesAutomatically) { + int spacing = (getViewportWidth() - mInsets.left - mInsets.right + - referenceChildWidth) / 2; + if (spacing >= 0) { + setPageSpacing(spacing); + } + mSpacePagesAutomatically = false; + } setMeasuredDimension(scaledWidthSize, scaledHeightSize); } + /** + * This method should be called once before first layout / measure pass. + */ + protected void setSinglePageInViewport() { + mSpacePagesAutomatically = true; + } + @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { if (!mIsDataReady || getChildCount() == 0) { @@ -974,9 +999,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc } if (mFirstLayout && mCurrentPage >= 0 && mCurrentPage < getChildCount()) { - setHorizontalScrollBarEnabled(false); updateCurrentPageScroll(); - setHorizontalScrollBarEnabled(true); mFirstLayout = false; } @@ -1105,7 +1128,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc return offset; } - protected void getOverviewModePages(int[] range) { + protected void getFreeScrollPageRange(int[] range) { range[0] = 0; range[1] = Math.max(0, getChildCount() - 1); } @@ -1158,7 +1181,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc } protected boolean shouldDrawChild(View child) { - return child.getAlpha() > 0 && child.getVisibility() == VISIBLE; + return child.getVisibility() == VISIBLE; } @Override @@ -1580,29 +1603,20 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc return f * f * f + 1.0f; } - protected void acceleratedOverScroll(float amount) { + protected float acceleratedOverFactor(float amount) { int screenSize = getViewportWidth(); // We want to reach the max over scroll effect when the user has // over scrolled half the size of the screen float f = OVERSCROLL_ACCELERATE_FACTOR * (amount / screenSize); - if (f == 0) return; + if (f == 0) return 0; // Clamp this factor, f, to -1 < f < 1 if (Math.abs(f) >= 1) { f /= Math.abs(f); } - - int overScrollAmount = (int) Math.round(f * screenSize); - if (amount < 0) { - mOverScrollX = overScrollAmount; - super.scrollTo(0, getScrollY()); - } else { - mOverScrollX = mMaxScrollX + overScrollAmount; - super.scrollTo(mMaxScrollX, getScrollY()); - } - invalidate(); + return f; } protected void dampedOverScroll(float amount) { @@ -1621,10 +1635,10 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc int overScrollAmount = (int) Math.round(OVERSCROLL_DAMP_FACTOR * f * screenSize); if (amount < 0) { mOverScrollX = overScrollAmount; - super.scrollTo(0, getScrollY()); + super.scrollTo(mOverScrollX, getScrollY()); } else { mOverScrollX = mMaxScrollX + overScrollAmount; - super.scrollTo(mMaxScrollX, getScrollY()); + super.scrollTo(mOverScrollX, getScrollY()); } invalidate(); } @@ -1650,7 +1664,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc } void updateFreescrollBounds() { - getOverviewModePages(mTempVisiblePagesRange); + getFreeScrollPageRange(mTempVisiblePagesRange); if (isLayoutRtl()) { mFreeScrollMinScrollX = getScrollForPage(mTempVisiblePagesRange[1]); mFreeScrollMaxScrollX = getScrollForPage(mTempVisiblePagesRange[0]); @@ -1665,7 +1679,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc if (mFreeScroll) { updateFreescrollBounds(); - getOverviewModePages(mTempVisiblePagesRange); + getFreeScrollPageRange(mTempVisiblePagesRange); if (getCurrentPage() < mTempVisiblePagesRange[0]) { setCurrentPage(mTempVisiblePagesRange[0]); } else if (getCurrentPage() > mTempVisiblePagesRange[1]) { @@ -1684,7 +1698,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc if (mDragView != null) { int dragX = (int) (mDragView.getLeft() + (mDragView.getMeasuredWidth() / 2) + mDragView.getTranslationX()); - getOverviewModePages(mTempVisiblePagesRange); + getFreeScrollPageRange(mTempVisiblePagesRange); int minDistance = Integer.MAX_VALUE; int minIndex = indexOfChild(mDragView); for (int i = mTempVisiblePagesRange[0]; i <= mTempVisiblePagesRange[1]; i++) { @@ -1801,7 +1815,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc !isHoveringOverDelete) { mTempVisiblePagesRange[0] = 0; mTempVisiblePagesRange[1] = getPageCount() - 1; - getOverviewModePages(mTempVisiblePagesRange); + getFreeScrollPageRange(mTempVisiblePagesRange); if (mTempVisiblePagesRange[0] <= pageUnderPointIndex && pageUnderPointIndex <= mTempVisiblePagesRange[1] && pageUnderPointIndex != mSidePageHoverIndex && mScroller.isFinished()) { @@ -2124,8 +2138,20 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc return minDistanceFromScreenCenterIndex; } + protected boolean isInOverScroll() { + return (mOverScrollX > mMaxScrollX || mOverScrollX < 0); + } + + protected int getPageSnapDuration() { + if (isInOverScroll()) { + return OVER_SCROLL_PAGE_SNAP_ANIMATION_DURATION; + } + return PAGE_SNAP_ANIMATION_DURATION; + + } + protected void snapToDestination() { - snapToPage(getPageNearestToCenterOfScreen(), PAGE_SNAP_ANIMATION_DURATION); + snapToPage(getPageNearestToCenterOfScreen(), getPageSnapDuration()); } private static class ScrollInterpolator implements Interpolator { @@ -2149,17 +2175,17 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc } protected void snapToPageWithVelocity(int whichPage, int velocity) { - whichPage = Math.max(0, Math.min(whichPage, getChildCount() - 1)); + whichPage = validateNewPage(whichPage); int halfScreenSize = getViewportWidth() / 2; final int newX = getScrollForPage(whichPage); int delta = newX - mUnboundedScrollX; int duration = 0; - if (Math.abs(velocity) < mMinFlingVelocity) { + if (Math.abs(velocity) < mMinFlingVelocity || isInOverScroll()) { // If the velocity is low enough, then treat this more as an automatic page advance // as opposed to an apparent physical response to flinging - snapToPage(whichPage, PAGE_SNAP_ANIMATION_DURATION); + snapToPage(whichPage, getPageSnapDuration()); return; } @@ -2183,11 +2209,11 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc } protected void snapToPage(int whichPage) { - snapToPage(whichPage, PAGE_SNAP_ANIMATION_DURATION); + snapToPage(whichPage, getPageSnapDuration()); } protected void snapToPageImmediately(int whichPage) { - snapToPage(whichPage, PAGE_SNAP_ANIMATION_DURATION, true, null); + snapToPage(whichPage, getPageSnapDuration(), true, null); } protected void snapToPage(int whichPage, int duration) { @@ -2200,7 +2226,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc protected void snapToPage(int whichPage, int duration, boolean immediate, TimeInterpolator interpolator) { - whichPage = Math.max(0, Math.min(whichPage, getPageCount() - 1)); + whichPage = validateNewPage(whichPage); int newX = getScrollForPage(whichPage); final int sX = mUnboundedScrollX; @@ -2214,6 +2240,8 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc protected void snapToPage(int whichPage, int delta, int duration, boolean immediate, TimeInterpolator interpolator) { + whichPage = validateNewPage(whichPage); + mNextPage = whichPage; View focusedChild = getFocusedChild(); if (focusedChild != null && whichPage != mCurrentPage && @@ -2482,11 +2510,11 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc public boolean startReordering(View v) { int dragViewIndex = indexOfChild(v); - if (mTouchState != TOUCH_STATE_REST) return false; + if (mTouchState != TOUCH_STATE_REST || dragViewIndex == -1) return false; mTempVisiblePagesRange[0] = 0; mTempVisiblePagesRange[1] = getPageCount() - 1; - getOverviewModePages(mTempVisiblePagesRange); + getFreeScrollPageRange(mTempVisiblePagesRange); mReorderingStarted = true; // Check if we are within the reordering range @@ -2619,7 +2647,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc // in the layout) // NOTE: We can make an assumption here because we have side-bound pages that we // will always have pages to animate in from the left - getOverviewModePages(mTempVisiblePagesRange); + getFreeScrollPageRange(mTempVisiblePagesRange); boolean isLastWidgetPage = (mTempVisiblePagesRange[0] == mTempVisiblePagesRange[1]); boolean slideFromLeft = (isLastWidgetPage || dragViewIndex > mTempVisiblePagesRange[0]); diff --git a/src/com/android/launcher3/PagedViewGridLayout.java b/src/com/android/launcher3/PagedViewGridLayout.java index b28686113..f69fa562d 100644 --- a/src/com/android/launcher3/PagedViewGridLayout.java +++ b/src/com/android/launcher3/PagedViewGridLayout.java @@ -56,18 +56,6 @@ public class PagedViewGridLayout extends GridLayout implements Page { } } - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - // PagedView currently has issues with different-sized pages since it calculates the - // offset of each page to scroll to before it updates the actual size of each page - // (which can change depending on the content if the contents aren't a fixed size). - // We work around this by having a minimum size on each widget page). - int widthSpecSize = Math.min(getSuggestedMinimumWidth(), - MeasureSpec.getSize(widthMeasureSpec)); - int widthSpecMode = MeasureSpec.EXACTLY; - super.onMeasure(MeasureSpec.makeMeasureSpec(widthSpecSize, widthSpecMode), - heightMeasureSpec); - } - @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); diff --git a/src/com/android/launcher3/PagedViewIcon.java b/src/com/android/launcher3/PagedViewIcon.java deleted file mode 100644 index f7cb997cd..000000000 --- a/src/com/android/launcher3/PagedViewIcon.java +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright (C) 2010 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.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.Region; -import android.graphics.drawable.Drawable; -import android.util.AttributeSet; -import android.util.TypedValue; -import android.widget.TextView; - -/** - * An icon on a PagedView, specifically for items in the launcher's paged view (with compound - * drawables on the top). - */ -public class PagedViewIcon extends TextView { - /** A simple callback interface to allow a PagedViewIcon to notify when it has been pressed */ - public static interface PressedCallback { - void iconPressed(PagedViewIcon icon); - } - - @SuppressWarnings("unused") - private static final String TAG = "PagedViewIcon"; - private static final float PRESS_ALPHA = 0.4f; - - private PagedViewIcon.PressedCallback mPressedCallback; - private boolean mLockDrawableState = false; - - private Bitmap mIcon; - - public PagedViewIcon(Context context) { - this(context, null); - } - - public PagedViewIcon(Context context, AttributeSet attrs) { - this(context, attrs, 0); - } - - public PagedViewIcon(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - } - - public void onFinishInflate() { - super.onFinishInflate(); - - // Ensure we are using the right text size - LauncherAppState app = LauncherAppState.getInstance(); - DeviceProfile grid = app.getDynamicGrid().getDeviceProfile(); - setTextSize(TypedValue.COMPLEX_UNIT_PX, grid.allAppsIconTextSizePx); - } - - public void applyFromApplicationInfo(AppInfo info, boolean scaleUp, - PagedViewIcon.PressedCallback cb) { - LauncherAppState app = LauncherAppState.getInstance(); - DeviceProfile grid = app.getDynamicGrid().getDeviceProfile(); - - mIcon = info.iconBitmap; - mPressedCallback = cb; - Drawable icon = Utilities.createIconDrawable(mIcon); - icon.setBounds(0, 0, grid.allAppsIconSizePx, grid.allAppsIconSizePx); - setCompoundDrawables(null, icon, null, null); - setCompoundDrawablePadding(grid.iconDrawablePaddingPx); - setText(info.title); - setTag(info); - } - - public void lockDrawableState() { - mLockDrawableState = true; - } - - public void resetDrawableState() { - mLockDrawableState = false; - post(new Runnable() { - @Override - public void run() { - refreshDrawableState(); - } - }); - } - - protected void drawableStateChanged() { - super.drawableStateChanged(); - - // We keep in the pressed state until resetDrawableState() is called to reset the press - // feedback - if (isPressed()) { - setAlpha(PRESS_ALPHA); - if (mPressedCallback != null) { - mPressedCallback.iconPressed(this); - } - } else if (!mLockDrawableState) { - setAlpha(1f); - } - } - - @Override - public void draw(Canvas canvas) { - // If text is transparent, don't draw any shadow - if (getCurrentTextColor() == getResources().getColor(android.R.color.transparent)) { - getPaint().clearShadowLayer(); - super.draw(canvas); - return; - } - - // We enhance the shadow by drawing the shadow twice - getPaint().setShadowLayer(BubbleTextView.SHADOW_LARGE_RADIUS, 0.0f, - BubbleTextView.SHADOW_Y_OFFSET, BubbleTextView.SHADOW_LARGE_COLOUR); - super.draw(canvas); - canvas.save(Canvas.CLIP_SAVE_FLAG); - canvas.clipRect(getScrollX(), getScrollY() + getExtendedPaddingTop(), - getScrollX() + getWidth(), - getScrollY() + getHeight(), Region.Op.INTERSECT); - getPaint().setShadowLayer(BubbleTextView.SHADOW_SMALL_RADIUS, 0.0f, 0.0f, - BubbleTextView.SHADOW_SMALL_COLOUR); - super.draw(canvas); - canvas.restore(); - } -} diff --git a/src/com/android/launcher3/PagedViewIconCache.java b/src/com/android/launcher3/PagedViewIconCache.java deleted file mode 100644 index 93887ea23..000000000 --- a/src/com/android/launcher3/PagedViewIconCache.java +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright (C) 2011 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.appwidget.AppWidgetProviderInfo; -import android.content.ComponentName; -import android.content.pm.ComponentInfo; -import android.content.pm.ResolveInfo; -import android.graphics.Bitmap; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; - -/** - * Simple cache mechanism for PagedView outlines. - */ -public class PagedViewIconCache { - public static class Key { - public enum Type { - ApplicationInfoKey, - AppWidgetProviderInfoKey, - ResolveInfoKey - } - private final ComponentName mComponentName; - private final Type mType; - - public Key(AppInfo info) { - mComponentName = info.componentName; - mType = Type.ApplicationInfoKey; - } - public Key(ResolveInfo info) { - final ComponentInfo ci = info.activityInfo != null ? info.activityInfo : - info.serviceInfo; - mComponentName = new ComponentName(ci.packageName, ci.name); - mType = Type.ResolveInfoKey; - } - public Key(AppWidgetProviderInfo info) { - mComponentName = info.provider; - mType = Type.AppWidgetProviderInfoKey; - } - - private ComponentName getComponentName() { - return mComponentName; - } - public boolean isKeyType(Type t) { - return (mType == t); - } - - @Override - public boolean equals(Object o) { - if (o instanceof Key) { - Key k = (Key) o; - return mComponentName.equals(k.mComponentName); - } - return super.equals(o); - } - @Override - public int hashCode() { - return getComponentName().hashCode(); - } - } - - private final HashMap<Key, Bitmap> mIconOutlineCache = new HashMap<Key, Bitmap>(); - - public void clear() { - for (Key key : mIconOutlineCache.keySet()) { - mIconOutlineCache.get(key).recycle(); - } - mIconOutlineCache.clear(); - } - private void retainAll(HashSet<Key> keysToKeep, Key.Type t) { - HashSet<Key> keysToRemove = new HashSet<Key>(mIconOutlineCache.keySet()); - keysToRemove.removeAll(keysToKeep); - for (Key key : keysToRemove) { - if (key.isKeyType(t)) { - mIconOutlineCache.get(key).recycle(); - mIconOutlineCache.remove(key); - } - } - } - /** Removes all the keys to applications that aren't in the passed in collection */ - public void retainAllApps(ArrayList<AppInfo> keys) { - HashSet<Key> keysSet = new HashSet<Key>(); - for (AppInfo info : keys) { - keysSet.add(new Key(info)); - } - retainAll(keysSet, Key.Type.ApplicationInfoKey); - } - /** Removes all the keys to shortcuts that aren't in the passed in collection */ - public void retainAllShortcuts(List<ResolveInfo> keys) { - HashSet<Key> keysSet = new HashSet<Key>(); - for (ResolveInfo info : keys) { - keysSet.add(new Key(info)); - } - retainAll(keysSet, Key.Type.ResolveInfoKey); - } - /** Removes all the keys to widgets that aren't in the passed in collection */ - public void retainAllAppWidgets(List<AppWidgetProviderInfo> keys) { - HashSet<Key> keysSet = new HashSet<Key>(); - for (AppWidgetProviderInfo info : keys) { - keysSet.add(new Key(info)); - } - retainAll(keysSet, Key.Type.AppWidgetProviderInfoKey); - } - public void addOutline(Key key, Bitmap b) { - mIconOutlineCache.put(key, b); - } - public void removeOutline(Key key) { - if (mIconOutlineCache.containsKey(key)) { - mIconOutlineCache.get(key).recycle(); - mIconOutlineCache.remove(key); - } - } - public Bitmap getOutline(Key key) { - return mIconOutlineCache.get(key); - } -} diff --git a/src/com/android/launcher3/PagedViewWidget.java b/src/com/android/launcher3/PagedViewWidget.java index db4aeb940..e6e11a312 100644 --- a/src/com/android/launcher3/PagedViewWidget.java +++ b/src/com/android/launcher3/PagedViewWidget.java @@ -30,6 +30,8 @@ import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; +import com.android.launcher3.compat.AppWidgetManagerCompat; + /** * The linear layout used strictly for the widget/wallpaper tab of the customization tray */ @@ -127,7 +129,7 @@ public class PagedViewWidget extends LinearLayout { image.setMaxWidth(maxWidth); } final TextView name = (TextView) findViewById(R.id.widget_name); - name.setText(info.label); + name.setText(AppWidgetManagerCompat.getInstance(getContext()).loadLabel(info)); final TextView dims = (TextView) findViewById(R.id.widget_dims); if (dims != null) { int hSpan = Math.min(cellSpan[0], (int) grid.numColumns); diff --git a/src/com/android/launcher3/Partner.java b/src/com/android/launcher3/Partner.java new file mode 100644 index 000000000..e1913193b --- /dev/null +++ b/src/com/android/launcher3/Partner.java @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2014 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.pm.PackageManager; +import android.content.res.Resources; +import android.util.DisplayMetrics; +import android.util.Log; +import android.util.Pair; + +import java.io.File; + +/** + * Utilities to discover and interact with partner customizations. There can + * only be one set of customizations on a device, and it must be bundled with + * the system. + */ +public class Partner { + + static final String TAG = "Launcher.Partner"; + + /** Marker action used to discover partner */ + private static final String + ACTION_PARTNER_CUSTOMIZATION = "com.android.launcher3.action.PARTNER_CUSTOMIZATION"; + + public static final String RES_FOLDER = "partner_folder"; + public static final String RES_WALLPAPERS = "partner_wallpapers"; + public static final String RES_DEFAULT_LAYOUT = "partner_default_layout"; + + public static final String RES_DEFAULT_WALLPAPER_HIDDEN = "default_wallpapper_hidden"; + public static final String RES_SYSTEM_WALLPAPER_DIR = "system_wallpaper_directory"; + + public static final String RES_REQUIRE_FIRST_RUN_FLOW = "requires_first_run_flow"; + + /** These resources are used to override the device profile */ + public static final String RES_GRID_AA_SHORT_EDGE_COUNT = "grid_aa_short_edge_count"; + public static final String RES_GRID_AA_LONG_EDGE_COUNT = "grid_aa_long_edge_count"; + public static final String RES_GRID_NUM_ROWS = "grid_num_rows"; + public static final String RES_GRID_NUM_COLUMNS = "grid_num_columns"; + public static final String RES_GRID_ICON_SIZE_DP = "grid_icon_size_dp"; + + private static boolean sSearched = false; + private static Partner sPartner; + + /** + * Find and return partner details, or {@code null} if none exists. + */ + public static synchronized Partner get(PackageManager pm) { + if (!sSearched) { + Pair<String, Resources> apkInfo = Utilities.findSystemApk(ACTION_PARTNER_CUSTOMIZATION, pm); + if (apkInfo != null) { + sPartner = new Partner(apkInfo.first, apkInfo.second); + } + sSearched = true; + } + return sPartner; + } + + private final String mPackageName; + private final Resources mResources; + + private Partner(String packageName, Resources res) { + mPackageName = packageName; + mResources = res; + } + + public String getPackageName() { + return mPackageName; + } + + public Resources getResources() { + return mResources; + } + + public boolean hasDefaultLayout() { + int defaultLayout = getResources().getIdentifier(Partner.RES_DEFAULT_LAYOUT, + "xml", getPackageName()); + return defaultLayout != 0; + } + + public boolean hasFolder() { + int folder = getResources().getIdentifier(Partner.RES_FOLDER, + "xml", getPackageName()); + return folder != 0; + } + + public boolean hideDefaultWallpaper() { + int resId = getResources().getIdentifier(RES_DEFAULT_WALLPAPER_HIDDEN, "bool", + getPackageName()); + return resId != 0 && getResources().getBoolean(resId); + } + + public File getWallpaperDirectory() { + int resId = getResources().getIdentifier(RES_SYSTEM_WALLPAPER_DIR, "string", + getPackageName()); + return (resId != 0) ? new File(getResources().getString(resId)) : null; + } + + public boolean requiresFirstRunFlow() { + int resId = getResources().getIdentifier(RES_REQUIRE_FIRST_RUN_FLOW, "bool", + getPackageName()); + return resId != 0 && getResources().getBoolean(resId); + } + + public DeviceProfile getDeviceProfileOverride(DisplayMetrics dm) { + boolean containsProfileOverrides = false; + + DeviceProfile dp = new DeviceProfile(); + + // We initialize customizable fields to be invalid + dp.numRows = -1; + dp.numColumns = -1; + dp.allAppsShortEdgeCount = -1; + dp.allAppsLongEdgeCount = -1; + + try { + int resId = getResources().getIdentifier(RES_GRID_NUM_ROWS, + "integer", getPackageName()); + if (resId > 0) { + containsProfileOverrides = true; + dp.numRows = getResources().getInteger(resId); + } + + resId = getResources().getIdentifier(RES_GRID_NUM_COLUMNS, + "integer", getPackageName()); + if (resId > 0) { + containsProfileOverrides = true; + dp.numColumns = getResources().getInteger(resId); + } + + resId = getResources().getIdentifier(RES_GRID_AA_SHORT_EDGE_COUNT, + "integer", getPackageName()); + if (resId > 0) { + containsProfileOverrides = true; + dp.allAppsShortEdgeCount = getResources().getInteger(resId); + } + + resId = getResources().getIdentifier(RES_GRID_AA_LONG_EDGE_COUNT, + "integer", getPackageName()); + if (resId > 0) { + containsProfileOverrides = true; + dp.allAppsLongEdgeCount = getResources().getInteger(resId); + } + + resId = getResources().getIdentifier(RES_GRID_ICON_SIZE_DP, + "dimen", getPackageName()); + if (resId > 0) { + containsProfileOverrides = true; + int px = getResources().getDimensionPixelSize(resId); + dp.iconSize = DynamicGrid.dpiFromPx(px, dm); + } + } catch (Resources.NotFoundException ex) { + Log.e(TAG, "Invalid Partner grid resource!", ex); + } + return containsProfileOverrides ? dp : null; + } +} diff --git a/src/com/android/launcher3/PendingAppWidgetHostView.java b/src/com/android/launcher3/PendingAppWidgetHostView.java new file mode 100644 index 000000000..d23a33033 --- /dev/null +++ b/src/com/android/launcher3/PendingAppWidgetHostView.java @@ -0,0 +1,241 @@ +/* + * Copyright (C) 2014 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.content.Intent; +import android.content.res.Resources.Theme; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; +import android.os.Bundle; +import android.text.Layout; +import android.text.StaticLayout; +import android.text.TextPaint; +import android.util.TypedValue; +import android.view.View; +import android.view.View.OnClickListener; + +public class PendingAppWidgetHostView extends LauncherAppWidgetHostView implements OnClickListener { + + private static Theme sPreloaderTheme; + + private final Rect mRect = new Rect(); + private View mDefaultView; + private OnClickListener mClickListener; + private final LauncherAppWidgetInfo mInfo; + private final int mStartState; + private final Intent mIconLookupIntent; + + private Bitmap mIcon; + private PreloadIconDrawable mDrawable; + + private Drawable mCenterDrawable; + private Drawable mTopCornerDrawable; + + private boolean mDrawableSizeChanged; + + private final TextPaint mPaint; + private Layout mSetupTextLayout; + + public PendingAppWidgetHostView(Context context, LauncherAppWidgetInfo info) { + super(context); + mInfo = info; + mStartState = info.restoreStatus; + mIconLookupIntent = new Intent().setComponent(info.providerName); + + mPaint = new TextPaint(); + mPaint.setColor(0xFFFFFFFF); + mPaint.setTextSize(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, + getDeviceProfile().iconTextSizePx, getResources().getDisplayMetrics())); + setBackgroundResource(R.drawable.quantum_panel_dark); + setWillNotDraw(false); + } + + @Override + public void updateAppWidgetSize(Bundle newOptions, int minWidth, int minHeight, int maxWidth, + int maxHeight) { + // No-op + } + + @Override + protected View getDefaultView() { + if (mDefaultView == null) { + mDefaultView = mInflater.inflate(R.layout.appwidget_not_ready, this, false); + mDefaultView.setOnClickListener(this); + applyState(); + } + return mDefaultView; + } + + @Override + public void setOnClickListener(OnClickListener l) { + mClickListener = l; + } + + @Override + public boolean isReinflateRequired() { + // Re inflate is required any time the widget restore status changes + return mStartState != mInfo.restoreStatus; + } + + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + super.onSizeChanged(w, h, oldw, oldh); + mDrawableSizeChanged = true; + } + + public void updateIcon(IconCache cache) { + Bitmap icon = cache.getIcon(mIconLookupIntent, mInfo.user); + if (mIcon == icon) { + return; + } + mIcon = icon; + if (mDrawable != null) { + mDrawable.setCallback(null); + mDrawable = null; + } + if (mIcon != null) { + // The view displays two modes, one with a setup icon and another with a preload icon + // in the center. + if (isReadyForClickSetup()) { + mCenterDrawable = getResources().getDrawable(R.drawable.ic_setting); + mTopCornerDrawable = new FastBitmapDrawable(mIcon); + } else { + if (sPreloaderTheme == null) { + sPreloaderTheme = getResources().newTheme(); + sPreloaderTheme.applyStyle(R.style.PreloadIcon, true); + } + + FastBitmapDrawable drawable = Utilities.createIconDrawable(mIcon); + mDrawable = new PreloadIconDrawable(drawable, sPreloaderTheme); + mDrawable.setCallback(this); + applyState(); + } + mDrawableSizeChanged = true; + } + } + + @Override + protected boolean verifyDrawable(Drawable who) { + return (who == mDrawable) || super.verifyDrawable(who); + } + + public void applyState() { + if (mDrawable != null) { + mDrawable.setLevel(Math.max(mInfo.installProgress, 0)); + } + } + + @Override + public void onClick(View v) { + // AppWidgetHostView blocks all click events on the root view. Instead handle click events + // on the content and pass it along. + if (mClickListener != null) { + mClickListener.onClick(this); + } + } + + public boolean isReadyForClickSetup() { + return (mInfo.restoreStatus & LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY) == 0 + && (mInfo.restoreStatus & LauncherAppWidgetInfo.FLAG_UI_NOT_READY) != 0; + } + + @Override + protected void onDraw(Canvas canvas) { + if (mDrawable != null) { + if (mDrawableSizeChanged) { + int maxSize = LauncherAppState.getInstance().getDynamicGrid() + .getDeviceProfile().iconSizePx + 2 * mDrawable.getOutset(); + int size = Math.min(maxSize, Math.min( + getWidth() - getPaddingLeft() - getPaddingRight(), + getHeight() - getPaddingTop() - getPaddingBottom())); + + mRect.set(0, 0, size, size); + mRect.inset(mDrawable.getOutset(), mDrawable.getOutset()); + mRect.offsetTo((getWidth() - mRect.width()) / 2, (getHeight() - mRect.height()) / 2); + mDrawable.setBounds(mRect); + mDrawableSizeChanged = false; + } + + mDrawable.draw(canvas); + } else if ((mCenterDrawable != null) && (mTopCornerDrawable != null)) { + if (mDrawableSizeChanged) { + DeviceProfile grid = getDeviceProfile(); + int iconSize = grid.iconSizePx; + int paddingTop = getPaddingTop(); + int paddingBottom = getPaddingBottom(); + int paddingLeft = getPaddingLeft(); + int paddingRight = getPaddingRight(); + + int availableWidth = getWidth() - paddingLeft - paddingRight; + int availableHeight = getHeight() - paddingTop - paddingBottom; + + // Recreate the setup text. + mSetupTextLayout = new StaticLayout( + getResources().getText(R.string.gadget_setup_text), mPaint, availableWidth, + Layout.Alignment.ALIGN_CENTER, 1, 0, true); + if (mSetupTextLayout.getLineCount() == 1) { + // The text fits in a single line. No need to draw the setup icon. + int size = Math.min(iconSize, Math.min(availableWidth, + availableHeight - mSetupTextLayout.getHeight())); + mRect.set(0, 0, size, size); + mRect.offsetTo((getWidth() - mRect.width()) / 2, + (getHeight() - mRect.height() - mSetupTextLayout.getHeight() + - grid.iconDrawablePaddingPx) / 2); + + mTopCornerDrawable.setBounds(mRect); + + // Update left and top to indicate the position where the text will be drawn. + mRect.left = paddingLeft; + mRect.top = mRect.bottom + grid.iconDrawablePaddingPx; + } else { + // The text can't be drawn in a single line. Draw a setup icon instead. + mSetupTextLayout = null; + int size = Math.min(iconSize, Math.min( + getWidth() - paddingLeft - paddingRight, + getHeight() - paddingTop - paddingBottom)); + mRect.set(0, 0, size, size); + mRect.offsetTo((getWidth() - mRect.width()) / 2, (getHeight() - mRect.height()) / 2); + mCenterDrawable.setBounds(mRect); + + size = Math.min(size / 2, + Math.max(mRect.top - paddingTop, mRect.left - paddingLeft)); + mTopCornerDrawable.setBounds(paddingLeft, paddingTop, + paddingLeft + size, paddingTop + size); + } + mDrawableSizeChanged = false; + } + + if (mSetupTextLayout == null) { + mCenterDrawable.draw(canvas); + mTopCornerDrawable.draw(canvas); + } else { + canvas.save(); + canvas.translate(mRect.left, mRect.top); + mSetupTextLayout.draw(canvas); + canvas.restore(); + mTopCornerDrawable.draw(canvas); + } + } + } + + private DeviceProfile getDeviceProfile() { + return LauncherAppState.getInstance().getDynamicGrid().getDeviceProfile(); + } +} diff --git a/src/com/android/launcher3/PreloadIconDrawable.java b/src/com/android/launcher3/PreloadIconDrawable.java new file mode 100644 index 000000000..2972c4f9b --- /dev/null +++ b/src/com/android/launcher3/PreloadIconDrawable.java @@ -0,0 +1,249 @@ +package com.android.launcher3; + +import android.animation.ObjectAnimator; +import android.content.res.Resources.Theme; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.ColorFilter; +import android.graphics.Paint; +import android.graphics.PixelFormat; +import android.graphics.Rect; +import android.graphics.RectF; +import android.graphics.drawable.Drawable; + +class PreloadIconDrawable extends Drawable { + + private static final float ANIMATION_PROGRESS_STOPPED = -1.0f; + private static final float ANIMATION_PROGRESS_STARTED = 0f; + private static final float ANIMATION_PROGRESS_COMPLETED = 1.0f; + + private static final float MIN_SATUNATION = 0.2f; + private static final float MIN_LIGHTNESS = 0.6f; + + private static final float ICON_SCALE_FACTOR = 0.5f; + private static final int DEFAULT_COLOR = 0xFF009688; + + private static final Rect sTempRect = new Rect(); + + private final RectF mIndicatorRect = new RectF(); + private boolean mIndicatorRectDirty; + + private final Paint mPaint; + final Drawable mIcon; + + private Drawable mBgDrawable; + private int mRingOutset; + + private int mIndicatorColor = 0; + + /** + * Indicates the progress of the preloader [0-100]. If it goes above 100, only the icon + * is shown with no progress bar. + */ + private int mProgress = 0; + + private float mAnimationProgress = ANIMATION_PROGRESS_STOPPED; + private ObjectAnimator mAnimator; + + public PreloadIconDrawable(Drawable icon, Theme theme) { + mIcon = icon; + + mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + mPaint.setStyle(Paint.Style.STROKE); + mPaint.setStrokeCap(Paint.Cap.ROUND); + + setBounds(icon.getBounds()); + applyTheme(theme); + onLevelChange(0); + } + + @Override + public void applyTheme(Theme t) { + TypedArray ta = t.obtainStyledAttributes(R.styleable.PreloadIconDrawable); + mBgDrawable = ta.getDrawable(R.styleable.PreloadIconDrawable_background); + mBgDrawable.setFilterBitmap(true); + mPaint.setStrokeWidth(ta.getDimension(R.styleable.PreloadIconDrawable_indicatorSize, 0)); + mRingOutset = ta.getDimensionPixelSize(R.styleable.PreloadIconDrawable_ringOutset, 0); + ta.recycle(); + onBoundsChange(getBounds()); + invalidateSelf(); + } + + @Override + protected void onBoundsChange(Rect bounds) { + mIcon.setBounds(bounds); + if (mBgDrawable != null) { + sTempRect.set(bounds); + sTempRect.inset(-mRingOutset, -mRingOutset); + mBgDrawable.setBounds(sTempRect); + } + mIndicatorRectDirty = true; + } + + public int getOutset() { + return mRingOutset; + } + + /** + * The size of the indicator is same as the content region of the {@link #mBgDrawable} minus + * half the stroke size to accommodate the indicator. + */ + private void initIndicatorRect() { + Drawable d = mBgDrawable; + Rect bounds = d.getBounds(); + + d.getPadding(sTempRect); + // Amount by which padding has to be scaled + float paddingScaleX = ((float) bounds.width()) / d.getIntrinsicWidth(); + float paddingScaleY = ((float) bounds.height()) / d.getIntrinsicHeight(); + mIndicatorRect.set( + bounds.left + sTempRect.left * paddingScaleX, + bounds.top + sTempRect.top * paddingScaleY, + bounds.right - sTempRect.right * paddingScaleX, + bounds.bottom - sTempRect.bottom * paddingScaleY); + + float inset = mPaint.getStrokeWidth() / 2; + mIndicatorRect.inset(inset, inset); + mIndicatorRectDirty = false; + } + + @Override + public void draw(Canvas canvas) { + final Rect r = new Rect(getBounds()); + if (canvas.getClipBounds(sTempRect) && !Rect.intersects(sTempRect, r)) { + // The draw region has been clipped. + return; + } + if (mIndicatorRectDirty) { + initIndicatorRect(); + } + final float iconScale; + + if ((mAnimationProgress >= ANIMATION_PROGRESS_STARTED) + && (mAnimationProgress < ANIMATION_PROGRESS_COMPLETED)) { + mPaint.setAlpha((int) ((1 - mAnimationProgress) * 255)); + mBgDrawable.setAlpha(mPaint.getAlpha()); + mBgDrawable.draw(canvas); + canvas.drawOval(mIndicatorRect, mPaint); + + iconScale = ICON_SCALE_FACTOR + (1 - ICON_SCALE_FACTOR) * mAnimationProgress; + } else if (mAnimationProgress == ANIMATION_PROGRESS_STOPPED) { + mPaint.setAlpha(255); + iconScale = ICON_SCALE_FACTOR; + mBgDrawable.setAlpha(255); + mBgDrawable.draw(canvas); + + if (mProgress >= 100) { + canvas.drawOval(mIndicatorRect, mPaint); + } else if (mProgress > 0) { + canvas.drawArc(mIndicatorRect, -90, mProgress * 3.6f, false, mPaint); + } + } else { + iconScale = 1; + } + + canvas.save(); + canvas.scale(iconScale, iconScale, r.exactCenterX(), r.exactCenterY()); + mIcon.draw(canvas); + canvas.restore(); + } + + @Override + public int getOpacity() { + return PixelFormat.TRANSLUCENT; + } + + @Override + public void setAlpha(int alpha) { + mIcon.setAlpha(alpha); + } + + @Override + public void setColorFilter(ColorFilter cf) { + mIcon.setColorFilter(cf); + } + + @Override + protected boolean onLevelChange(int level) { + mProgress = level; + + // Stop Animation + if (mAnimator != null) { + mAnimator.cancel(); + mAnimator = null; + } + mAnimationProgress = ANIMATION_PROGRESS_STOPPED; + if (level > 0) { + // Set the paint color only when the level changes, so that the dominant color + // is only calculated when needed. + mPaint.setColor(getIndicatorColor()); + } + if (mIcon instanceof FastBitmapDrawable) { + ((FastBitmapDrawable) mIcon).setGhostModeEnabled(level <= 0); + } + + invalidateSelf(); + return true; + } + + /** + * Runs the finish animation if it is has not been run after last level change. + */ + public void maybePerformFinishedAnimation() { + if (mAnimationProgress > ANIMATION_PROGRESS_STOPPED) { + return; + } + if (mAnimator != null) { + mAnimator.cancel(); + } + setAnimationProgress(ANIMATION_PROGRESS_STARTED); + mAnimator = ObjectAnimator.ofFloat(this, "animationProgress", + ANIMATION_PROGRESS_STARTED, ANIMATION_PROGRESS_COMPLETED); + mAnimator.start(); + } + + public void setAnimationProgress(float progress) { + if (progress != mAnimationProgress) { + mAnimationProgress = progress; + invalidateSelf(); + } + } + + public float getAnimationProgress() { + return mAnimationProgress; + } + + @Override + public int getIntrinsicHeight() { + return mIcon.getIntrinsicHeight(); + } + + @Override + public int getIntrinsicWidth() { + return mIcon.getIntrinsicWidth(); + } + + private int getIndicatorColor() { + if (mIndicatorColor != 0) { + return mIndicatorColor; + } + if (!(mIcon instanceof FastBitmapDrawable)) { + mIndicatorColor = DEFAULT_COLOR; + return mIndicatorColor; + } + mIndicatorColor = Utilities.findDominantColorByHue( + ((FastBitmapDrawable) mIcon).getBitmap(), 20); + + // Make sure that the dominant color has enough saturation to be visible properly. + float[] hsv = new float[3]; + Color.colorToHSV(mIndicatorColor, hsv); + if (hsv[1] < MIN_SATUNATION) { + mIndicatorColor = DEFAULT_COLOR; + return mIndicatorColor; + } + hsv[2] = Math.max(MIN_LIGHTNESS, hsv[2]); + mIndicatorColor = Color.HSVToColor(hsv); + return mIndicatorColor; + } +} diff --git a/src/com/android/launcher3/PreloadReceiver.java b/src/com/android/launcher3/PreloadReceiver.java deleted file mode 100644 index ca25746eb..000000000 --- a/src/com/android/launcher3/PreloadReceiver.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (C) 2012 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.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.os.AsyncTask; -import android.text.TextUtils; -import android.util.Log; - -public class PreloadReceiver extends BroadcastReceiver { - private static final String TAG = "Launcher.PreloadReceiver"; - private static final boolean LOGD = false; - - public static final String EXTRA_WORKSPACE_NAME = - "com.android.launcher3.action.EXTRA_WORKSPACE_NAME"; - - @Override - public void onReceive(Context context, Intent intent) { - final LauncherProvider provider = LauncherAppState.getLauncherProvider(); - if (provider != null) { - String name = intent.getStringExtra(EXTRA_WORKSPACE_NAME); - final int workspaceResId = !TextUtils.isEmpty(name) - ? context.getResources().getIdentifier(name, "xml", "com.android.launcher3") : 0; - if (LOGD) { - Log.d(TAG, "workspace name: " + name + " id: " + workspaceResId); - } - new AsyncTask<Void, Void, Void>() { - public Void doInBackground(Void ... args) { - provider.loadDefaultFavoritesIfNecessary(workspaceResId); - return null; - } - }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void) null); - } - } -} diff --git a/src/com/android/launcher3/ScrimView.java b/src/com/android/launcher3/ScrimView.java deleted file mode 100644 index 68200fe64..000000000 --- a/src/com/android/launcher3/ScrimView.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C) 2011 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.graphics.Rect; -import android.util.AttributeSet; -import android.widget.FrameLayout; - -public class ScrimView extends FrameLayout implements Insettable { - - public ScrimView(Context context) { - this(context, null, 0); - } - - public ScrimView(Context context, AttributeSet attrs) { - this(context, attrs, 0); - } - - public ScrimView(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - } - - @Override - public void setInsets(Rect insets) { - // Do nothing - } -} diff --git a/src/com/android/launcher3/ShortcutInfo.java b/src/com/android/launcher3/ShortcutInfo.java index 79d114c06..daf343460 100644 --- a/src/com/android/launcher3/ShortcutInfo.java +++ b/src/com/android/launcher3/ShortcutInfo.java @@ -20,18 +20,44 @@ import android.content.ComponentName; import android.content.ContentValues; import android.content.Context; import android.content.Intent; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; -import android.content.pm.PackageManager.NameNotFoundException; import android.graphics.Bitmap; import android.util.Log; +import com.android.launcher3.compat.UserHandleCompat; + import java.util.ArrayList; +import java.util.Arrays; /** * Represents a launchable icon on the workspaces and in folders. */ -class ShortcutInfo extends ItemInfo { +public class ShortcutInfo extends ItemInfo { + + public static final int DEFAULT = 0; + + /** + * The shortcut was restored from a backup and it not ready to be used. This is automatically + * set during backup/restore + */ + public static final int FLAG_RESTORED_ICON = 1; + + /** + * The icon was added as an auto-install app, and is not ready to be used. This flag can't + * be present along with {@link #FLAG_RESTORED_ICON}, and is set during default layout + * parsing. + */ + public static final int FLAG_AUTOINTALL_ICON = 2; + + /** + * The icon is being installed. If {@link FLAG_RESTORED_ICON} or {@link FLAG_AUTOINTALL_ICON} + * is set, then the icon is either being installed or is in a broken state. + */ + public static final int FLAG_INSTALL_SESSION_ACTIVE = 4; + + /** + * Indicates that the widget restore has started. + */ + public static final int FLAG_RESTORE_STARTED = 8; /** * The intent used to start the application. @@ -61,43 +87,52 @@ class ShortcutInfo extends ItemInfo { */ private Bitmap mIcon; + /** + * Could be disabled, if the the app is installed but unavailable (eg. in safe mode or when + * sd-card is not available). + */ + boolean isDisabled = false; + + int status; + + /** + * The installation progress [0-100] of the package that this shortcut represents. + */ + private int mInstallProgress; + + /** + * Refer {@link AppInfo#firstInstallTime}. + */ long firstInstallTime; + + /** + * TODO move this to {@link status} + */ int flags = 0; /** * If this shortcut is a placeholder, then intent will be a market intent for the package, and * this will hold the original intent from the database. Otherwise, null. + * Refer {@link #FLAG_RESTORE_PENDING}, {@link #FLAG_INSTALL_PENDING} */ - Intent restoredIntent; + Intent promisedIntent; ShortcutInfo() { itemType = LauncherSettings.BaseLauncherColumns.ITEM_TYPE_SHORTCUT; } - protected Intent getIntent() { + public Intent getIntent() { return intent; } - protected Intent getRestoredIntent() { - return restoredIntent; - } - - /** - * Overwrite placeholder data with restored data, or do nothing if this is not a placeholder. - */ - public void restore() { - if (restoredIntent != null) { - intent = restoredIntent; - restoredIntent = null; - } - } - - - ShortcutInfo(Intent intent, CharSequence title, Bitmap icon) { + ShortcutInfo(Intent intent, CharSequence title, CharSequence contentDescription, + Bitmap icon, UserHandleCompat user) { this(); this.intent = intent; this.title = title; + this.contentDescription = contentDescription; mIcon = icon; + this.user = user; } public ShortcutInfo(Context context, ShortcutInfo info) { @@ -111,8 +146,10 @@ class ShortcutInfo extends ItemInfo { } mIcon = info.mIcon; // TODO: should make a copy here. maybe we don't need this ctor at all customIcon = info.customIcon; - initFlagsAndFirstInstallTime( - getPackageInfo(context, intent.getComponent().getPackageName())); + flags = info.flags; + firstInstallTime = info.firstInstallTime; + user = info.user; + status = info.status; } /** TODO: Remove this. It's only called by ApplicationInfo.makeShortcut. */ @@ -125,22 +162,6 @@ class ShortcutInfo extends ItemInfo { firstInstallTime = info.firstInstallTime; } - public static PackageInfo getPackageInfo(Context context, String packageName) { - PackageInfo pi = null; - try { - PackageManager pm = context.getPackageManager(); - pi = pm.getPackageInfo(packageName, 0); - } catch (NameNotFoundException e) { - Log.d("ShortcutInfo", "PackageManager.getPackageInfo failed for " + packageName); - } - return pi; - } - - void initFlagsAndFirstInstallTime(PackageInfo pi) { - flags = AppInfo.initFlags(pi); - firstInstallTime = AppInfo.initFirstInstallTime(pi); - } - public void setIcon(Bitmap b) { mIcon = b; } @@ -153,35 +174,19 @@ class ShortcutInfo extends ItemInfo { } public void updateIcon(IconCache iconCache) { - mIcon = iconCache.getIcon(intent); - usingFallbackIcon = iconCache.isDefaultIcon(mIcon); - } - - /** - * Creates the application intent based on a component name and various launch flags. - * Sets {@link #itemType} to {@link LauncherSettings.BaseLauncherColumns#ITEM_TYPE_APPLICATION}. - * - * @param className the class name of the component representing the intent - * @param launchFlags the launch flags - */ - final void setActivity(Context context, ComponentName className, int launchFlags) { - intent = new Intent(Intent.ACTION_MAIN); - intent.addCategory(Intent.CATEGORY_LAUNCHER); - intent.setComponent(className); - intent.setFlags(launchFlags); - itemType = LauncherSettings.BaseLauncherColumns.ITEM_TYPE_APPLICATION; - initFlagsAndFirstInstallTime( - getPackageInfo(context, intent.getComponent().getPackageName())); + mIcon = iconCache.getIcon(promisedIntent != null ? promisedIntent : intent, user); + usingFallbackIcon = iconCache.isDefaultIcon(mIcon, user); } @Override - void onAddToDatabase(ContentValues values) { - super.onAddToDatabase(values); + void onAddToDatabase(Context context, ContentValues values) { + super.onAddToDatabase(context, values); String titleStr = title != null ? title.toString() : null; values.put(LauncherSettings.BaseLauncherColumns.TITLE, titleStr); - String uri = intent != null ? intent.toUri(0) : null; + String uri = promisedIntent != null ? promisedIntent.toUri(0) + : (intent != null ? intent.toUri(0) : null); values.put(LauncherSettings.BaseLauncherColumns.INTENT, uri); if (customIcon) { @@ -205,10 +210,10 @@ class ShortcutInfo extends ItemInfo { @Override public String toString() { - return "ShortcutInfo(title=" + title.toString() + "intent=" + intent + "id=" + this.id + return "ShortcutInfo(title=" + title + "intent=" + intent + "id=" + this.id + " type=" + this.itemType + " container=" + this.container + " screen=" + screenId + " cellX=" + cellX + " cellY=" + cellY + " spanX=" + spanX + " spanY=" + spanY - + " dropPos=" + dropPos + ")"; + + " dropPos=" + Arrays.toString(dropPos) + " user=" + user + ")"; } public static void dumpShortcutInfoList(String tag, String label, @@ -219,5 +224,27 @@ class ShortcutInfo extends ItemInfo { + " customIcon=" + info.customIcon); } } + + public ComponentName getTargetComponent() { + return promisedIntent != null ? promisedIntent.getComponent() : intent.getComponent(); + } + + public boolean hasStatusFlag(int flag) { + return (status & flag) != 0; + } + + + public final boolean isPromise() { + return hasStatusFlag(FLAG_RESTORED_ICON | FLAG_AUTOINTALL_ICON); + } + + public int getInstallProgress() { + return mInstallProgress; + } + + public void setInstallProgress(int progress) { + mInstallProgress = progress; + status |= FLAG_INSTALL_SESSION_ACTIVE; + } } diff --git a/src/com/android/launcher3/StartupReceiver.java b/src/com/android/launcher3/StartupReceiver.java new file mode 100644 index 000000000..65f913fdf --- /dev/null +++ b/src/com/android/launcher3/StartupReceiver.java @@ -0,0 +1,15 @@ +package com.android.launcher3; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; + +public class StartupReceiver extends BroadcastReceiver { + + static final String SYSTEM_READY = "com.android.launcher3.SYSTEM_READY"; + + @Override + public void onReceive(Context context, Intent intent) { + context.sendStickyBroadcast(new Intent(SYSTEM_READY)); + } +} diff --git a/src/com/android/launcher3/Stats.java b/src/com/android/launcher3/Stats.java index 882fb04a3..f3977e456 100644 --- a/src/com/android/launcher3/Stats.java +++ b/src/com/android/launcher3/Stats.java @@ -32,7 +32,6 @@ public class Stats { private static final boolean LOCAL_LAUNCH_LOG = true; public static final String ACTION_LAUNCH = "com.android.launcher3.action.LAUNCH"; - public static final String PERM_LAUNCH = "com.android.launcher3.permission.RECEIVE_LAUNCH_BROADCASTS"; public static final String EXTRA_INTENT = "intent"; public static final String EXTRA_CONTAINER = "container"; public static final String EXTRA_SCREEN = "screen"; @@ -53,6 +52,8 @@ public class Stats { private final Launcher mLauncher; + private final String mLaunchBroadcastPermission; + DataOutputStream mLog; ArrayList<String> mIntents; @@ -61,6 +62,9 @@ public class Stats { public Stats(Launcher launcher) { mLauncher = launcher; + mLaunchBroadcastPermission = + launcher.getResources().getString(R.string.receive_launch_broadcasts_permission); + loadStats(); if (LOCAL_LAUNCH_LOG) { @@ -87,7 +91,7 @@ public class Stats { } }, new IntentFilter(ACTION_LAUNCH), - PERM_LAUNCH, + mLaunchBroadcastPermission, null ); } @@ -120,7 +124,7 @@ public class Stats { .putExtra(EXTRA_CELLX, shortcut.cellX) .putExtra(EXTRA_CELLY, shortcut.cellY); } - mLauncher.sendBroadcast(broadcastIntent, PERM_LAUNCH); + mLauncher.sendBroadcast(broadcastIntent, mLaunchBroadcastPermission); incrementLaunch(flat); diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java index cbc978585..80d4b22ce 100644 --- a/src/com/android/launcher3/Utilities.java +++ b/src/com/android/launcher3/Utilities.java @@ -18,14 +18,18 @@ package com.android.launcher3; import android.app.Activity; import android.content.ActivityNotFoundException; +import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; +import android.content.pm.ResolveInfo; import android.content.res.Resources; import android.graphics.Bitmap; -import android.graphics.BlurMaskFilter; import android.graphics.Canvas; -import android.graphics.ColorMatrix; -import android.graphics.ColorMatrixColorFilter; +import android.graphics.Color; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.PaintFlagsDrawFilter; @@ -33,8 +37,10 @@ import android.graphics.Rect; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.PaintDrawable; -import android.util.DisplayMetrics; +import android.os.Build; import android.util.Log; +import android.util.Pair; +import android.util.SparseArray; import android.view.View; import android.widget.Toast; @@ -51,10 +57,6 @@ public final class Utilities { public static int sIconTextureWidth = -1; public static int sIconTextureHeight = -1; - private static final Paint sBlurPaint = new Paint(); - private static final Paint sGlowColorPressedPaint = new Paint(); - private static final Paint sGlowColorFocusedPaint = new Paint(); - private static final Paint sDisabledPaint = new Paint(); private static final Rect sOldBounds = new Rect(); private static final Canvas sCanvas = new Canvas(); @@ -65,6 +67,8 @@ public final class Utilities { static int sColors[] = { 0xffff0000, 0xff00ff00, 0xff0000ff }; static int sColorIndex = 0; + static int[] sLoc0 = new int[2]; + static int[] sLoc1 = new int[2]; // To turn on these properties, type // adb shell setprop log.tag.PROPERTY_NAME [VERBOSE | SUPPRESS] @@ -74,7 +78,7 @@ public final class Utilities { /** * Returns a FastBitmapDrawable with the icon, accurately sized. */ - static Drawable createIconDrawable(Bitmap icon) { + public static FastBitmapDrawable createIconDrawable(Bitmap icon) { FastBitmapDrawable d = new FastBitmapDrawable(icon); d.setFilterBitmap(true); resizeIconDrawable(d); @@ -99,6 +103,13 @@ public final class Utilities { } /** + * Indicates if the device is running LMP or higher. + */ + public static boolean isLmpOrAbove() { + return Build.VERSION.SDK_INT >= Build.VERSION_CODES.L; + } + + /** * Returns a bitmap suitable for the all apps view. Used to convert pre-ICS * icon bitmaps that are stored in the database (which were 74x74 pixels at hdpi size) * to the proper size (48dp) @@ -305,22 +316,21 @@ public final class Utilities { return scale; } + /** + * Utility method to determine whether the given point, in local coordinates, + * is inside the view, where the area of the view is expanded by the slop factor. + * This method is called while processing touch-move events to determine if the event + * is still within the view. + */ + public static boolean pointInView(View v, float localX, float localY, float slop) { + return localX >= -slop && localY >= -slop && localX < (v.getWidth() + slop) && + localY < (v.getHeight() + slop); + } + private static void initStatics(Context context) { final Resources resources = context.getResources(); - final DisplayMetrics metrics = resources.getDisplayMetrics(); - final float density = metrics.density; - sIconWidth = sIconHeight = (int) resources.getDimension(R.dimen.app_icon_size); sIconTextureWidth = sIconTextureHeight = sIconWidth; - - sBlurPaint.setMaskFilter(new BlurMaskFilter(5 * density, BlurMaskFilter.Blur.NORMAL)); - sGlowColorPressedPaint.setColor(0xffffc300); - sGlowColorFocusedPaint.setColor(0xffff8e00); - - ColorMatrix cm = new ColorMatrix(); - cm.setSaturation(0.2f); - sDisabledPaint.setColorFilter(new ColorMatrixColorFilter(cm)); - sDisabledPaint.setAlpha(0x88); } public static void setIconSize(int widthPx) { @@ -337,6 +347,25 @@ public final class Utilities { } } + public static int[] getCenterDeltaInScreenSpace(View v0, View v1, int[] delta) { + v0.getLocationInWindow(sLoc0); + v1.getLocationInWindow(sLoc1); + + sLoc0[0] += (v0.getMeasuredWidth() * v0.getScaleX()) / 2; + sLoc0[1] += (v0.getMeasuredHeight() * v0.getScaleY()) / 2; + sLoc1[0] += (v1.getMeasuredWidth() * v1.getScaleX()) / 2; + sLoc1[1] += (v1.getMeasuredHeight() * v1.getScaleY()) / 2; + + if (delta == null) { + delta = new int[2]; + } + + delta[0] = sLoc1[0] - sLoc0[0]; + delta[1] = sLoc1[1] - sLoc0[1]; + + return delta; + } + public static void scaleRectAboutCenter(Rect r, float scale) { int cx = r.centerX(); int cy = r.centerY(); @@ -358,4 +387,130 @@ public final class Utilities { "or use the exported attribute for this activity.", e); } } + + static boolean isSystemApp(Context context, Intent intent) { + PackageManager pm = context.getPackageManager(); + ComponentName cn = intent.getComponent(); + String packageName = null; + if (cn == null) { + ResolveInfo info = pm.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY); + if ((info != null) && (info.activityInfo != null)) { + packageName = info.activityInfo.packageName; + } + } else { + packageName = cn.getPackageName(); + } + if (packageName != null) { + try { + PackageInfo info = pm.getPackageInfo(packageName, 0); + return (info != null) && (info.applicationInfo != null) && + ((info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0); + } catch (NameNotFoundException e) { + return false; + } + } else { + return false; + } + } + + /** + * This picks a dominant color, looking for high-saturation, high-value, repeated hues. + * @param bitmap The bitmap to scan + * @param samples The approximate max number of samples to use. + */ + static int findDominantColorByHue(Bitmap bitmap, int samples) { + final int height = bitmap.getHeight(); + final int width = bitmap.getWidth(); + int sampleStride = (int) Math.sqrt((height * width) / samples); + if (sampleStride < 1) { + sampleStride = 1; + } + + // This is an out-param, for getting the hsv values for an rgb + float[] hsv = new float[3]; + + // First get the best hue, by creating a histogram over 360 hue buckets, + // where each pixel contributes a score weighted by saturation, value, and alpha. + float[] hueScoreHistogram = new float[360]; + float highScore = -1; + int bestHue = -1; + + for (int y = 0; y < height; y += sampleStride) { + for (int x = 0; x < width; x += sampleStride) { + int argb = bitmap.getPixel(x, y); + int alpha = 0xFF & (argb >> 24); + if (alpha < 0x80) { + // Drop mostly-transparent pixels. + continue; + } + // Remove the alpha channel. + int rgb = argb | 0xFF000000; + Color.colorToHSV(rgb, hsv); + // Bucket colors by the 360 integer hues. + int hue = (int) hsv[0]; + if (hue < 0 || hue >= hueScoreHistogram.length) { + // Defensively avoid array bounds violations. + continue; + } + float score = hsv[1] * hsv[2]; + hueScoreHistogram[hue] += score; + if (hueScoreHistogram[hue] > highScore) { + highScore = hueScoreHistogram[hue]; + bestHue = hue; + } + } + } + + SparseArray<Float> rgbScores = new SparseArray<Float>(); + int bestColor = 0xff000000; + highScore = -1; + // Go back over the RGB colors that match the winning hue, + // creating a histogram of weighted s*v scores, for up to 100*100 [s,v] buckets. + // The highest-scoring RGB color wins. + for (int y = 0; y < height; y += sampleStride) { + for (int x = 0; x < width; x += sampleStride) { + int rgb = bitmap.getPixel(x, y) | 0xff000000; + Color.colorToHSV(rgb, hsv); + int hue = (int) hsv[0]; + if (hue == bestHue) { + float s = hsv[1]; + float v = hsv[2]; + int bucket = (int) (s * 100) + (int) (v * 10000); + // Score by cumulative saturation * value. + float score = s * v; + Float oldTotal = rgbScores.get(bucket); + float newTotal = oldTotal == null ? score : oldTotal + score; + rgbScores.put(bucket, newTotal); + if (newTotal > highScore) { + highScore = newTotal; + // All the colors in the winning bucket are very similar. Last in wins. + bestColor = rgb; + } + } + } + } + return bestColor; + } + + /* + * Finds a system apk which had a broadcast receiver listening to a particular action. + * @param action intent action used to find the apk + * @return a pair of apk package name and the resources. + */ + static Pair<String, Resources> findSystemApk(String action, PackageManager pm) { + final Intent intent = new Intent(action); + for (ResolveInfo info : pm.queryBroadcastReceivers(intent, 0)) { + if (info.activityInfo != null && + (info.activityInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) { + final String packageName = info.activityInfo.packageName; + try { + final Resources res = pm.getResourcesForApplication(packageName); + return Pair.create(packageName, res); + } catch (NameNotFoundException e) { + Log.w(TAG, "Failed to find resources for " + packageName); + } + } + } + return null; + } } diff --git a/src/com/android/launcher3/WidgetAdder.java b/src/com/android/launcher3/WidgetAdder.java deleted file mode 100644 index 79ac50492..000000000 --- a/src/com/android/launcher3/WidgetAdder.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.android.launcher3; - -import android.app.Activity; - -public class WidgetAdder extends Activity { - -} diff --git a/src/com/android/launcher3/WidgetPreviewLoader.java b/src/com/android/launcher3/WidgetPreviewLoader.java index 3db0b51ad..5aa719027 100644 --- a/src/com/android/launcher3/WidgetPreviewLoader.java +++ b/src/com/android/launcher3/WidgetPreviewLoader.java @@ -5,16 +5,17 @@ import android.content.ComponentName; import android.content.ContentValues; import android.content.Context; import android.content.SharedPreferences; -import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.res.Resources; import android.database.Cursor; +import android.database.sqlite.SQLiteCantOpenDatabaseException; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDiskIOException; import android.database.sqlite.SQLiteOpenHelper; import android.graphics.Bitmap; import android.graphics.Bitmap.Config; import android.graphics.BitmapFactory; +import android.graphics.BitmapShader; import android.graphics.Canvas; import android.graphics.ColorMatrix; import android.graphics.ColorMatrixColorFilter; @@ -27,129 +28,138 @@ import android.graphics.drawable.Drawable; import android.os.AsyncTask; import android.util.Log; +import com.android.launcher3.compat.AppWidgetManagerCompat; + import java.io.ByteArrayOutputStream; import java.io.File; +import java.io.IOException; import java.lang.ref.SoftReference; import java.lang.ref.WeakReference; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; +import java.util.List; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; -abstract class SoftReferenceThreadLocal<T> { - private ThreadLocal<SoftReference<T>> mThreadLocal; - public SoftReferenceThreadLocal() { - mThreadLocal = new ThreadLocal<SoftReference<T>>(); - } +public class WidgetPreviewLoader { - abstract T initialValue(); + private static abstract class SoftReferenceThreadLocal<T> { + private ThreadLocal<SoftReference<T>> mThreadLocal; + public SoftReferenceThreadLocal() { + mThreadLocal = new ThreadLocal<SoftReference<T>>(); + } - public void set(T t) { - mThreadLocal.set(new SoftReference<T>(t)); - } + abstract T initialValue(); - public T get() { - SoftReference<T> reference = mThreadLocal.get(); - T obj; - if (reference == null) { - obj = initialValue(); - mThreadLocal.set(new SoftReference<T>(obj)); - return obj; - } else { - obj = reference.get(); - if (obj == null) { + public void set(T t) { + mThreadLocal.set(new SoftReference<T>(t)); + } + + public T get() { + SoftReference<T> reference = mThreadLocal.get(); + T obj; + if (reference == null) { obj = initialValue(); mThreadLocal.set(new SoftReference<T>(obj)); + return obj; + } else { + obj = reference.get(); + if (obj == null) { + obj = initialValue(); + mThreadLocal.set(new SoftReference<T>(obj)); + } + return obj; } - return obj; } } -} -class CanvasCache extends SoftReferenceThreadLocal<Canvas> { - @Override - protected Canvas initialValue() { - return new Canvas(); + private static class CanvasCache extends SoftReferenceThreadLocal<Canvas> { + @Override + protected Canvas initialValue() { + return new Canvas(); + } } -} -class PaintCache extends SoftReferenceThreadLocal<Paint> { - @Override - protected Paint initialValue() { - return null; + private static class PaintCache extends SoftReferenceThreadLocal<Paint> { + @Override + protected Paint initialValue() { + return null; + } } -} -class BitmapCache extends SoftReferenceThreadLocal<Bitmap> { - @Override - protected Bitmap initialValue() { - return null; + private static class BitmapCache extends SoftReferenceThreadLocal<Bitmap> { + @Override + protected Bitmap initialValue() { + return null; + } } -} -class RectCache extends SoftReferenceThreadLocal<Rect> { - @Override - protected Rect initialValue() { - return new Rect(); + private static class RectCache extends SoftReferenceThreadLocal<Rect> { + @Override + protected Rect initialValue() { + return new Rect(); + } } -} -class BitmapFactoryOptionsCache extends SoftReferenceThreadLocal<BitmapFactory.Options> { - @Override - protected BitmapFactory.Options initialValue() { - return new BitmapFactory.Options(); + private static class BitmapFactoryOptionsCache extends + SoftReferenceThreadLocal<BitmapFactory.Options> { + @Override + protected BitmapFactory.Options initialValue() { + return new BitmapFactory.Options(); + } } -} -public class WidgetPreviewLoader { - static final String TAG = "WidgetPreviewLoader"; - static final String ANDROID_INCREMENTAL_VERSION_NAME_KEY = "android.incremental.version"; + private static final String TAG = "WidgetPreviewLoader"; + private static final String ANDROID_INCREMENTAL_VERSION_NAME_KEY = "android.incremental.version"; + + private static final float WIDGET_PREVIEW_ICON_PADDING_PERCENTAGE = 0.25f; + private static final HashSet<String> sInvalidPackages = new HashSet<String>(); + + // Used for drawing shortcut previews + private final BitmapCache mCachedShortcutPreviewBitmap = new BitmapCache(); + private final PaintCache mCachedShortcutPreviewPaint = new PaintCache(); + private final CanvasCache mCachedShortcutPreviewCanvas = new CanvasCache(); + + // Used for drawing widget previews + private final CanvasCache mCachedAppWidgetPreviewCanvas = new CanvasCache(); + private final RectCache mCachedAppWidgetPreviewSrcRect = new RectCache(); + private final RectCache mCachedAppWidgetPreviewDestRect = new RectCache(); + private final PaintCache mCachedAppWidgetPreviewPaint = new PaintCache(); + private final PaintCache mDefaultAppWidgetPreviewPaint = new PaintCache(); + private final BitmapFactoryOptionsCache mCachedBitmapFactoryOptions = new BitmapFactoryOptionsCache(); + + private final HashMap<String, WeakReference<Bitmap>> mLoadedPreviews = new HashMap<>(); + private final ArrayList<SoftReference<Bitmap>> mUnusedBitmaps = new ArrayList<>(); + + private final Context mContext; + private final int mAppIconSize; + private final IconCache mIconCache; + private final AppWidgetManagerCompat mManager; private int mPreviewBitmapWidth; private int mPreviewBitmapHeight; private String mSize; - private Context mContext; - private PackageManager mPackageManager; private PagedViewCellLayout mWidgetSpacingLayout; - // Used for drawing shortcut previews - private BitmapCache mCachedShortcutPreviewBitmap = new BitmapCache(); - private PaintCache mCachedShortcutPreviewPaint = new PaintCache(); - private CanvasCache mCachedShortcutPreviewCanvas = new CanvasCache(); - - // Used for drawing widget previews - private CanvasCache mCachedAppWidgetPreviewCanvas = new CanvasCache(); - private RectCache mCachedAppWidgetPreviewSrcRect = new RectCache(); - private RectCache mCachedAppWidgetPreviewDestRect = new RectCache(); - private PaintCache mCachedAppWidgetPreviewPaint = new PaintCache(); private String mCachedSelectQuery; - private BitmapFactoryOptionsCache mCachedBitmapFactoryOptions = new BitmapFactoryOptionsCache(); - - private int mAppIconSize; - private IconCache mIconCache; - private final float sWidgetPreviewIconPaddingPercentage = 0.25f; private CacheDb mDb; - private HashMap<String, WeakReference<Bitmap>> mLoadedPreviews; - private ArrayList<SoftReference<Bitmap>> mUnusedBitmaps; - private static HashSet<String> sInvalidPackages; - - static { - sInvalidPackages = new HashSet<String>(); - } + private final MainThreadExecutor mMainThreadExecutor = new MainThreadExecutor(); public WidgetPreviewLoader(Context context) { LauncherAppState app = LauncherAppState.getInstance(); DeviceProfile grid = app.getDynamicGrid().getDeviceProfile(); mContext = context; - mPackageManager = mContext.getPackageManager(); mAppIconSize = grid.iconSizePx; mIconCache = app.getIconCache(); + mManager = AppWidgetManagerCompat.getInstance(context); + mDb = app.getWidgetPreviewCacheDb(); - mLoadedPreviews = new HashMap<String, WeakReference<Bitmap>>(); - mUnusedBitmaps = new ArrayList<SoftReference<Bitmap>>(); SharedPreferences sp = context.getSharedPreferences( LauncherAppState.getSharedPreferencesKey(), Context.MODE_PRIVATE); @@ -165,7 +175,7 @@ public class WidgetPreviewLoader { editor.commit(); } } - + public void recreateDb() { LauncherAppState app = LauncherAppState.getInstance(); app.recreateWidgetPreviewDb(); @@ -184,18 +194,19 @@ public class WidgetPreviewLoader { final String name = getObjectName(o); final String packageName = getObjectPackage(o); // check if the package is valid - boolean packageValid = true; synchronized(sInvalidPackages) { - packageValid = !sInvalidPackages.contains(packageName); - } - if (!packageValid) { - return null; + boolean packageValid = !sInvalidPackages.contains(packageName); + if (!packageValid) { + return null; + } } - if (packageValid) { - synchronized(mLoadedPreviews) { - // check if it exists in our existing cache - if (mLoadedPreviews.containsKey(name) && mLoadedPreviews.get(name).get() != null) { - return mLoadedPreviews.get(name).get(); + synchronized(mLoadedPreviews) { + // check if it exists in our existing cache + if (mLoadedPreviews.containsKey(name)) { + WeakReference<Bitmap> bitmapReference = mLoadedPreviews.get(name); + Bitmap bitmap = bitmapReference.get(); + if (bitmap != null) { + return bitmap; } } } @@ -203,11 +214,13 @@ public class WidgetPreviewLoader { Bitmap unusedBitmap = null; synchronized(mUnusedBitmaps) { // not in cache; we need to load it from the db - while ((unusedBitmap == null || !unusedBitmap.isMutable() || - unusedBitmap.getWidth() != mPreviewBitmapWidth || - unusedBitmap.getHeight() != mPreviewBitmapHeight) - && mUnusedBitmaps.size() > 0) { - unusedBitmap = mUnusedBitmaps.remove(0).get(); + while (unusedBitmap == null && mUnusedBitmaps.size() > 0) { + Bitmap candidate = mUnusedBitmaps.remove(0).get(); + if (candidate != null && candidate.isMutable() && + candidate.getWidth() == mPreviewBitmapWidth && + candidate.getHeight() == mPreviewBitmapHeight) { + unusedBitmap = candidate; + } } if (unusedBitmap != null) { final Canvas c = mCachedAppWidgetPreviewCanvas.get(); @@ -221,12 +234,7 @@ public class WidgetPreviewLoader { unusedBitmap = Bitmap.createBitmap(mPreviewBitmapWidth, mPreviewBitmapHeight, Bitmap.Config.ARGB_8888); } - - Bitmap preview = null; - - if (packageValid) { - preview = readFromDb(name, unusedBitmap); - } + Bitmap preview = readFromDb(name, unusedBitmap); if (preview != null) { synchronized(mLoadedPreviews) { @@ -320,7 +328,7 @@ public class WidgetPreviewLoader { String output; if (o instanceof AppWidgetProviderInfo) { sb.append(WIDGET_PREFIX); - sb.append(((AppWidgetProviderInfo) o).provider.flattenToString()); + sb.append(((AppWidgetProviderInfo) o).toString()); output = sb.toString(); sb.setLength(0); } else { @@ -358,6 +366,9 @@ public class WidgetPreviewLoader { db.insert(CacheDb.TABLE_NAME, null, values); } catch (SQLiteDiskIOException e) { recreateDb(); + } catch (SQLiteCantOpenDatabaseException e) { + dumpOpenFiles(); + throw e; } } @@ -367,6 +378,9 @@ public class WidgetPreviewLoader { try { db.delete(CacheDb.TABLE_NAME, null, null); } catch (SQLiteDiskIOException e) { + } catch (SQLiteCantOpenDatabaseException e) { + dumpOpenFiles(); + throw e; } } @@ -387,6 +401,9 @@ public class WidgetPreviewLoader { } // args to SELECT query ); } catch (SQLiteDiskIOException e) { + } catch (SQLiteCantOpenDatabaseException e) { + dumpOpenFiles(); + throw e; } synchronized(sInvalidPackages) { sInvalidPackages.remove(packageName); @@ -396,7 +413,7 @@ public class WidgetPreviewLoader { }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void) null); } - public static void removeItemFromDb(final CacheDb cacheDb, final String objectName) { + private static void removeItemFromDb(final CacheDb cacheDb, final String objectName) { new AsyncTask<Void, Void, Void>() { public Void doInBackground(Void ... args) { SQLiteDatabase db = cacheDb.getWritableDatabase(); @@ -405,6 +422,9 @@ public class WidgetPreviewLoader { CacheDb.COLUMN_NAME + " = ? ", // SELECT query new String[] { objectName }); // args to SELECT query } catch (SQLiteDiskIOException e) { + } catch (SQLiteCantOpenDatabaseException e) { + dumpOpenFiles(); + throw e; } return null; } @@ -430,6 +450,9 @@ public class WidgetPreviewLoader { } catch (SQLiteDiskIOException e) { recreateDb(); return null; + } catch (SQLiteCantOpenDatabaseException e) { + dumpOpenFiles(); + throw e; } if (result.getCount() > 0) { result.moveToFirst(); @@ -450,7 +473,7 @@ public class WidgetPreviewLoader { } } - public Bitmap generatePreview(Object info, Bitmap preview) { + private Bitmap generatePreview(Object info, Bitmap preview) { if (preview != null && (preview.getWidth() != mPreviewBitmapWidth || preview.getHeight() != mPreviewBitmapHeight)) { @@ -468,8 +491,8 @@ public class WidgetPreviewLoader { int[] cellSpans = Launcher.getSpanForWidget(mContext, info); int maxWidth = maxWidthForWidgetPreview(cellSpans[0]); int maxHeight = maxHeightForWidgetPreview(cellSpans[1]); - return generateWidgetPreview(info.provider, info.previewImage, info.icon, - cellSpans[0], cellSpans[1], maxWidth, maxHeight, preview, null); + return generateWidgetPreview(info, cellSpans[0], cellSpans[1], + maxWidth, maxHeight, preview, null); } public int maxWidthForWidgetPreview(int spanX) { @@ -482,20 +505,20 @@ public class WidgetPreviewLoader { mWidgetSpacingLayout.estimateCellHeight(spanY)); } - public Bitmap generateWidgetPreview(ComponentName provider, int previewImage, - int iconId, int cellHSpan, int cellVSpan, int maxPreviewWidth, int maxPreviewHeight, - Bitmap preview, int[] preScaledWidthOut) { + public Bitmap generateWidgetPreview(AppWidgetProviderInfo info, int cellHSpan, int cellVSpan, + int maxPreviewWidth, int maxPreviewHeight, Bitmap preview, int[] preScaledWidthOut) { // Load the preview image if possible - String packageName = provider.getPackageName(); if (maxPreviewWidth < 0) maxPreviewWidth = Integer.MAX_VALUE; if (maxPreviewHeight < 0) maxPreviewHeight = Integer.MAX_VALUE; Drawable drawable = null; - if (previewImage != 0) { - drawable = mPackageManager.getDrawable(packageName, previewImage, null); - if (drawable == null) { + if (info.previewImage != 0) { + drawable = mManager.loadPreview(info); + if (drawable != null) { + drawable = mutateOnMainThread(drawable); + } else { Log.w(TAG, "Can't load widget preview drawable 0x" + - Integer.toHexString(previewImage) + " for provider: " + provider); + Integer.toHexString(info.previewImage) + " for provider: " + info.provider); } } @@ -511,6 +534,7 @@ public class WidgetPreviewLoader { if (cellHSpan < 1) cellHSpan = 1; if (cellVSpan < 1) cellVSpan = 1; + // This Drawable is not directly drawn, so there's no need to mutate it. BitmapDrawable previewDrawable = (BitmapDrawable) mContext.getResources() .getDrawable(R.drawable.widget_tile); final int previewDrawableWidth = previewDrawable @@ -520,31 +544,33 @@ public class WidgetPreviewLoader { previewWidth = previewDrawableWidth * cellHSpan; previewHeight = previewDrawableHeight * cellVSpan; - defaultPreview = Bitmap.createBitmap(previewWidth, previewHeight, - Config.ARGB_8888); + defaultPreview = Bitmap.createBitmap(previewWidth, previewHeight, Config.ARGB_8888); final Canvas c = mCachedAppWidgetPreviewCanvas.get(); c.setBitmap(defaultPreview); - previewDrawable.setBounds(0, 0, previewWidth, previewHeight); - previewDrawable.setTileModeXY(Shader.TileMode.REPEAT, - Shader.TileMode.REPEAT); - previewDrawable.draw(c); + Paint p = mDefaultAppWidgetPreviewPaint.get(); + if (p == null) { + p = new Paint(); + p.setShader(new BitmapShader(previewDrawable.getBitmap(), + Shader.TileMode.REPEAT, Shader.TileMode.REPEAT)); + mDefaultAppWidgetPreviewPaint.set(p); + } + final Rect dest = mCachedAppWidgetPreviewDestRect.get(); + dest.set(0, 0, previewWidth, previewHeight); + c.drawRect(dest, p); c.setBitmap(null); // Draw the icon in the top left corner - int minOffset = (int) (mAppIconSize * sWidgetPreviewIconPaddingPercentage); + int minOffset = (int) (mAppIconSize * WIDGET_PREVIEW_ICON_PADDING_PERCENTAGE); int smallestSide = Math.min(previewWidth, previewHeight); float iconScale = Math.min((float) smallestSide / (mAppIconSize + 2 * minOffset), 1f); try { - Drawable icon = null; - int hoffset = - (int) ((previewDrawableWidth - mAppIconSize * iconScale) / 2); - int yoffset = - (int) ((previewDrawableHeight - mAppIconSize * iconScale) / 2); - if (iconId > 0) - icon = mIconCache.getFullResIcon(packageName, iconId); + Drawable icon = mManager.loadIcon(info, mIconCache); if (icon != null) { + int hoffset = (int) ((previewDrawableWidth - mAppIconSize * iconScale) / 2); + int yoffset = (int) ((previewDrawableHeight - mAppIconSize * iconScale) / 2); + icon = mutateOnMainThread(icon); renderDrawableToBitmap(icon, defaultPreview, hoffset, yoffset, (int) (mAppIconSize * iconScale), (int) (mAppIconSize * iconScale)); @@ -594,7 +620,7 @@ public class WidgetPreviewLoader { c.drawBitmap(defaultPreview, src, dest, p); c.setBitmap(null); } - return preview; + return mManager.getBadgeBitmap(info, preview); } private Bitmap generateShortcutPreview( @@ -612,7 +638,7 @@ public class WidgetPreviewLoader { c.setBitmap(null); } // Render the icon - Drawable icon = mIconCache.getFullResIcon(info); + Drawable icon = mutateOnMainThread(mIconCache.getFullResIcon(info)); int paddingTop = mContext. getResources().getDimensionPixelOffset(R.dimen.shortcut_preview_padding_top); @@ -652,18 +678,10 @@ public class WidgetPreviewLoader { return preview; } - - public static void renderDrawableToBitmap( - Drawable d, Bitmap bitmap, int x, int y, int w, int h) { - renderDrawableToBitmap(d, bitmap, x, y, w, h, 1f); - } - private static void renderDrawableToBitmap( - Drawable d, Bitmap bitmap, int x, int y, int w, int h, - float scale) { + Drawable d, Bitmap bitmap, int x, int y, int w, int h) { if (bitmap != null) { Canvas c = new Canvas(bitmap); - c.scale(scale, scale); Rect oldBounds = d.copyBounds(); d.setBounds(x, y, x + w, y + h); d.draw(c); @@ -672,4 +690,98 @@ public class WidgetPreviewLoader { } } + private Drawable mutateOnMainThread(final Drawable drawable) { + try { + return mMainThreadExecutor.submit(new Callable<Drawable>() { + @Override + public Drawable call() throws Exception { + return drawable.mutate(); + } + }).get(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new RuntimeException(e); + } catch (ExecutionException e) { + throw new RuntimeException(e); + } + } + + private static final int MAX_OPEN_FILES = 1024; + private static final int SAMPLE_RATE = 23; + /** + * Dumps all files that are open in this process without allocating a file descriptor. + */ + private static void dumpOpenFiles() { + try { + Log.i(TAG, "DUMP OF OPEN FILES (sample rate: 1 every " + SAMPLE_RATE + "):"); + final String TYPE_APK = "apk"; + final String TYPE_JAR = "jar"; + final String TYPE_PIPE = "pipe"; + final String TYPE_SOCKET = "socket"; + final String TYPE_DB = "db"; + final String TYPE_ANON_INODE = "anon_inode"; + final String TYPE_DEV = "dev"; + final String TYPE_NON_FS = "non-fs"; + final String TYPE_OTHER = "other"; + List<String> types = Arrays.asList(TYPE_APK, TYPE_JAR, TYPE_PIPE, TYPE_SOCKET, TYPE_DB, + TYPE_ANON_INODE, TYPE_DEV, TYPE_NON_FS, TYPE_OTHER); + int[] count = new int[types.size()]; + int[] duplicates = new int[types.size()]; + HashSet<String> files = new HashSet<String>(); + int total = 0; + for (int i = 0; i < MAX_OPEN_FILES; i++) { + // This is a gigantic hack but unfortunately the only way to resolve an fd + // to a file name. Note that we have to loop over all possible fds because + // reading the directory would require allocating a new fd. The kernel is + // currently implemented such that no fd is larger then the current rlimit, + // which is why it's safe to loop over them in such a way. + String fd = "/proc/self/fd/" + i; + try { + // getCanonicalPath() uses readlink behind the scene which doesn't require + // a file descriptor. + String resolved = new File(fd).getCanonicalPath(); + int type = types.indexOf(TYPE_OTHER); + if (resolved.startsWith("/dev/")) { + type = types.indexOf(TYPE_DEV); + } else if (resolved.endsWith(".apk")) { + type = types.indexOf(TYPE_APK); + } else if (resolved.endsWith(".jar")) { + type = types.indexOf(TYPE_JAR); + } else if (resolved.contains("/fd/pipe:")) { + type = types.indexOf(TYPE_PIPE); + } else if (resolved.contains("/fd/socket:")) { + type = types.indexOf(TYPE_SOCKET); + } else if (resolved.contains("/fd/anon_inode:")) { + type = types.indexOf(TYPE_ANON_INODE); + } else if (resolved.endsWith(".db") || resolved.contains("/databases/")) { + type = types.indexOf(TYPE_DB); + } else if (resolved.startsWith("/proc/") && resolved.contains("/fd/")) { + // Those are the files that don't point anywhere on the file system. + // getCanonicalPath() wrongly interprets these as relative symlinks and + // resolves them within /proc/<pid>/fd/. + type = types.indexOf(TYPE_NON_FS); + } + count[type]++; + total++; + if (files.contains(resolved)) { + duplicates[type]++; + } + files.add(resolved); + if (total % SAMPLE_RATE == 0) { + Log.i(TAG, " fd " + i + ": " + resolved + + " (" + types.get(type) + ")"); + } + } catch (IOException e) { + // Ignoring exceptions for non-existing file descriptors. + } + } + for (int i = 0; i < types.size(); i++) { + Log.i(TAG, String.format("Open %10s files: %4d total, %4d duplicates", + types.get(i), count[i], duplicates[i])); + } + } catch (Throwable t) { + // Catch everything. This is called from an exception handler that we shouldn't upset. + Log.e(TAG, "Unable to log open files.", t); + } + } } diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java index 567abfa47..774996e56 100644 --- a/src/com/android/launcher3/Workspace.java +++ b/src/com/android/launcher3/Workspace.java @@ -31,12 +31,16 @@ import android.appwidget.AppWidgetHostView; import android.appwidget.AppWidgetProviderInfo; 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.content.res.Resources; import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Matrix; +import android.graphics.Paint; import android.graphics.Point; import android.graphics.PointF; import android.graphics.Rect; @@ -44,6 +48,7 @@ import android.graphics.Region.Op; import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.AsyncTask; +import android.os.Handler; import android.os.IBinder; import android.os.Parcelable; import android.support.v4.view.ViewCompat; @@ -63,11 +68,17 @@ import android.widget.TextView; import com.android.launcher3.FolderIcon.FolderRingAnimator; import com.android.launcher3.Launcher.CustomContentCallbacks; import com.android.launcher3.LauncherSettings.Favorites; +import com.android.launcher3.compat.PackageInstallerCompat; +import com.android.launcher3.compat.PackageInstallerCompat.PackageInstallInfo; +import com.android.launcher3.compat.UserHandleCompat; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.atomic.AtomicInteger; /** * The workspace is a wide area with a wallpaper and a finite number of pages. @@ -96,6 +107,9 @@ public class Workspace extends SmoothPagedView private static final float ALPHA_CUTOFF_THRESHOLD = 0.01f; + static final boolean MAP_NO_RECURSE = false; + static final boolean MAP_RECURSE = true; + // These animators are used to fade the children's outlines private ObjectAnimator mChildrenOutlineFadeInAnimation; private ObjectAnimator mChildrenOutlineFadeOutAnimation; @@ -104,9 +118,6 @@ public class Workspace extends SmoothPagedView // These properties refer to the background protection gradient used for AllApps and Customize private ValueAnimator mBackgroundFadeInAnimation; private ValueAnimator mBackgroundFadeOutAnimation; - private Drawable mBackground; - boolean mDrawBackground = true; - private float mBackgroundAlpha = 0; private static final long CUSTOM_CONTENT_GESTURE_DELAY = 200; private long mTouchDownTime = -1; @@ -123,13 +134,14 @@ public class Workspace extends SmoothPagedView private static boolean sAccessibilityEnabled; // The screen id used for the empty screen always present to the right. - private final static long EXTRA_EMPTY_SCREEN_ID = -201; + final static long EXTRA_EMPTY_SCREEN_ID = -201; private final static long CUSTOM_CONTENT_SCREEN_ID = -301; private HashMap<Long, CellLayout> mWorkspaceScreens = new HashMap<Long, CellLayout>(); private ArrayList<Long> mScreenOrder = new ArrayList<Long>(); private Runnable mRemoveEmptyScreenRunnable; + private boolean mDeferRemoveExtraEmptyScreen = false; /** * CellInfo for the cell that is currently being dragged @@ -185,7 +197,7 @@ public class Workspace extends SmoothPagedView // State variable that indicates whether the pages are small (ie when you're // in all apps or customize mode) - enum State { NORMAL, SPRING_LOADED, SMALL, OVERVIEW}; + enum State { NORMAL, NORMAL_HIDDEN, SPRING_LOADED, OVERVIEW, OVERVIEW_HIDDEN}; private State mState = State.NORMAL; private boolean mIsSwitchingState = false; @@ -200,11 +212,10 @@ public class Workspace extends SmoothPagedView private HolographicOutlineHelper mOutlineHelper; private Bitmap mDragOutline = null; - private final Rect mTempRect = new Rect(); + private static final Rect sTempRect = new Rect(); private final int[] mTempXY = new int[2]; private int[] mTempVisiblePagesRange = new int[2]; - private boolean mOverscrollTransformsSet; - private float mLastOverscrollPivotX; + private boolean mOverscrollEffectSet; public static final int DRAG_BITMAP_PADDING = 2; private boolean mWorkspaceFadeInAdjacentScreens; @@ -230,6 +241,8 @@ public class Workspace extends SmoothPagedView private DropTarget.DragEnforcer mDragEnforcer; private float mMaxDistanceForFolderCreation; + private final Canvas mCanvas = new Canvas(); + // Variables relating to touch disambiguation (scrolling workspace vs. scrolling a widget) private float mXDown; private float mYDown; @@ -270,6 +283,8 @@ public class Workspace extends SmoothPagedView private int mLastChildCount = -1; private float mTransitionProgress; + float mOverScrollEffect = 0f; + private Runnable mDeferredAction; private boolean mDeferDropAfterUninstall; private boolean mUninstallSuccessful; @@ -392,13 +407,23 @@ public class Workspace extends SmoothPagedView @Override public void run() { if (mIsDragOccuring) { + mDeferRemoveExtraEmptyScreen = false; addExtraEmptyScreenOnDrag(); } } }); } + + public void deferRemoveExtraEmptyScreen() { + mDeferRemoveExtraEmptyScreen = true; + } + public void onDragEnd() { + if (!mDeferRemoveExtraEmptyScreen) { + removeExtraEmptyScreen(true, mDragSourceInternal != null); + } + mIsDragOccuring = false; updateChildrenLayersEnabled(false); mLauncher.unlockScreenOrientation(false); @@ -415,7 +440,6 @@ public class Workspace extends SmoothPagedView * Initializes various states for this workspace. */ protected void initWorkspace() { - Context context = getContext(); mCurrentPage = mDefaultPage; Launcher.setScreen(mCurrentPage); LauncherAppState app = LauncherAppState.getInstance(); @@ -429,13 +453,6 @@ public class Workspace extends SmoothPagedView setMinScale(mOverviewModeShrinkFactor); setupLayoutTransition(); - final Resources res = getResources(); - try { - mBackground = res.getDrawable(R.drawable.apps_customize_bg); - } catch (Resources.NotFoundException e) { - // In this case, we will skip drawing background protection - } - mWallpaperOffset = new WallpaperOffsetInterpolator(); Display display = mLauncher.getWindowManager().getDefaultDisplay(); display.getSize(mDisplaySize); @@ -570,6 +587,7 @@ public class Workspace extends SmoothPagedView CellLayout customScreen = (CellLayout) mLauncher.getLayoutInflater().inflate(R.layout.workspace_screen, null); customScreen.disableBackground(); + customScreen.disableDragTarget(); mWorkspaceScreens.put(CUSTOM_CONTENT_SCREEN_ID, customScreen); mScreenOrder.add(0, CUSTOM_CONTENT_SCREEN_ID); @@ -583,7 +601,6 @@ public class Workspace extends SmoothPagedView mDefaultPage = mOriginalDefaultPage + 1; // Update the custom content hint - mLauncher.getLauncherClings().updateCustomContentHintVisibility(); if (mRestorePage != INVALID_RESTORE_PAGE) { mRestorePage = mRestorePage + 1; } else { @@ -612,7 +629,6 @@ public class Workspace extends SmoothPagedView mDefaultPage = mOriginalDefaultPage - 1; // Update the custom content hint - mLauncher.getLauncherClings().updateCustomContentHintVisibility(); if (mRestorePage != INVALID_RESTORE_PAGE) { mRestorePage = mRestorePage - 1; } else { @@ -693,6 +709,12 @@ public class Workspace extends SmoothPagedView // Log to disk Launcher.addDumpLog(TAG, "11683562 - convertFinalScreenToEmptyScreenIfNecessary()", true); + if (mLauncher.isWorkspaceLoading()) { + // Invalid and dangerous operation if workspace is loading + Launcher.addDumpLog(TAG, " - workspace loading, skip", true); + return; + } + if (hasExtraEmptyScreen() || mScreenOrder.size() == 0) return; long finalScreenId = mScreenOrder.get(mScreenOrder.size() - 1); @@ -715,21 +737,26 @@ public class Workspace extends SmoothPagedView } } - public void removeExtraEmptyScreen(final boolean animate, final Runnable onComplete) { - removeExtraEmptyScreen(animate, onComplete, 0, false); + public void removeExtraEmptyScreen(final boolean animate, boolean stripEmptyScreens) { + removeExtraEmptyScreenDelayed(animate, null, 0, stripEmptyScreens); } - public void removeExtraEmptyScreen(final boolean animate, final Runnable onComplete, + public void removeExtraEmptyScreenDelayed(final boolean animate, final Runnable onComplete, final int delay, final boolean stripEmptyScreens) { // Log to disk Launcher.addDumpLog(TAG, "11683562 - removeExtraEmptyScreen()", true); + if (mLauncher.isWorkspaceLoading()) { + // Don't strip empty screens if the workspace is still loading + Launcher.addDumpLog(TAG, " - workspace loading, skip", true); + return; + } + if (delay > 0) { postDelayed(new Runnable() { @Override public void run() { - removeExtraEmptyScreen(animate, onComplete, 0, stripEmptyScreens); + removeExtraEmptyScreenDelayed(animate, onComplete, 0, stripEmptyScreens); } - }, delay); return; } @@ -807,6 +834,11 @@ public class Workspace extends SmoothPagedView public long commitExtraEmptyScreen() { // Log to disk Launcher.addDumpLog(TAG, "11683562 - commitExtraEmptyScreen()", true); + if (mLauncher.isWorkspaceLoading()) { + // Invalid and dangerous operation if workspace is loading + Launcher.addDumpLog(TAG, " - workspace loading, skip", true); + return -1; + } int index = getPageIndexForScreenId(EXTRA_EMPTY_SCREEN_ID); CellLayout cl = mWorkspaceScreens.get(EXTRA_EMPTY_SCREEN_ID); @@ -864,7 +896,8 @@ public class Workspace extends SmoothPagedView Launcher.addDumpLog(TAG, "11683562 - stripEmptyScreens()", true); if (mLauncher.isWorkspaceLoading()) { - // Don't strip empty screens if the workspace is still loading + // Don't strip empty screens if the workspace is still loading. + // This is dangerous and can result in data loss. Launcher.addDumpLog(TAG, " - workspace loading, skip", true); return; } @@ -969,7 +1002,7 @@ public class Workspace extends SmoothPagedView final CellLayout layout; if (container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) { layout = mLauncher.getHotseat().getLayout(); - child.setOnKeyListener(null); + child.setOnKeyListener(new HotseatIconKeyEventListener()); // Hide folder title in the hotseat if (child instanceof FolderIcon) { @@ -1035,8 +1068,8 @@ public class Workspace extends SmoothPagedView */ @Override public boolean onTouch(View v, MotionEvent event) { - return (isSmall() || !isFinishedSwitchingState()) - || (!isSmall() && indexOfChild(v) != mCurrentPage); + return (workspaceInModalState() || !isFinishedSwitchingState()) + || (!workspaceInModalState() && indexOfChild(v) != mCurrentPage); } public boolean isSwitchingState() { @@ -1055,7 +1088,7 @@ public class Workspace extends SmoothPagedView @Override public boolean dispatchUnhandledMove(View focused, int direction) { - if (isSmall() || !isFinishedSwitchingState()) { + if (workspaceInModalState() || !isFinishedSwitchingState()) { // when the home screens are shrunken, shouldn't allow side-scrolling return false; } @@ -1074,7 +1107,7 @@ public class Workspace extends SmoothPagedView case MotionEvent.ACTION_UP: if (mTouchState == TOUCH_STATE_REST) { final CellLayout currentPage = (CellLayout) getChildAt(mCurrentPage); - if (!currentPage.lastDownOnOccupiedCell()) { + if (currentPage != null && !currentPage.lastDownOnOccupiedCell()) { onWallpaperTap(ev); } } @@ -1082,6 +1115,17 @@ public class Workspace extends SmoothPagedView return super.onInterceptTouchEvent(ev); } + @Override + public boolean onGenericMotionEvent(MotionEvent event) { + // Ignore pointer scroll events if the custom content doesn't allow scrolling. + if ((getScreenIdForPageIndex(getCurrentPage()) == CUSTOM_CONTENT_SCREEN_ID) + && (mCustomContentCallbacks != null) + && !mCustomContentCallbacks.isScrollingAllowed()) { + return false; + } + return super.onGenericMotionEvent(event); + } + protected void reinflateWidgetsIfNecessary() { final int clCount = getChildCount(); for (int i = 0; i < clCount; i++) { @@ -1091,10 +1135,10 @@ public class Workspace extends SmoothPagedView for (int j = 0; j < itemCount; j++) { View v = swc.getChildAt(j); - if (v.getTag() instanceof LauncherAppWidgetInfo) { + if (v != null && v.getTag() instanceof LauncherAppWidgetInfo) { LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) v.getTag(); LauncherAppWidgetHostView lahv = (LauncherAppWidgetHostView) info.hostView; - if (lahv != null && lahv.orientationChangedSincedInflation()) { + if (lahv != null && lahv.isReinflateRequired()) { mLauncher.removeAppWidget(info); // Remove the current widget which is inflated with the wrong orientation cl.removeView(lahv); @@ -1126,12 +1170,20 @@ public class Workspace extends SmoothPagedView (mTouchDownTime - mCustomContentShowTime) > CUSTOM_CONTENT_GESTURE_DELAY; boolean swipeInIgnoreDirection = isLayoutRtl() ? deltaX < 0 : deltaX > 0; - if (swipeInIgnoreDirection && getScreenIdForPageIndex(getCurrentPage()) == - CUSTOM_CONTENT_SCREEN_ID && passRightSwipesToCustomContent) { + boolean onCustomContentScreen = + getScreenIdForPageIndex(getCurrentPage()) == CUSTOM_CONTENT_SCREEN_ID; + if (swipeInIgnoreDirection && onCustomContentScreen && passRightSwipesToCustomContent) { // Pass swipes to the right to the custom content page. return; } + if (onCustomContentScreen && (mCustomContentCallbacks != null) + && !mCustomContentCallbacks.isScrollingAllowed()) { + // Don't allow workspace scrolling if the current custom content screen doesn't allow + // scrolling. + return; + } + if (theta > MAX_SWIPE_ANGLE) { // Above MAX_SWIPE_ANGLE, we don't want to ever start scrolling the workspace return; @@ -1165,14 +1217,6 @@ public class Workspace extends SmoothPagedView enableChildrenCache(mCurrentPage - 1, mCurrentPage + 1); } } - - // If we are not fading in adjacent screens, we still need to restore the alpha in case the - // user scrolls while we are transitioning (should not affect dispatchDraw optimizations) - if (!mWorkspaceFadeInAdjacentScreens) { - for (int i = 0; i < getChildCount(); ++i) { - ((CellLayout) getPageAt(i)).setShortcutAndWidgetAlpha(1f); - } - } } protected void onPageEndMoving() { @@ -1185,7 +1229,7 @@ public class Workspace extends SmoothPagedView } if (mDragController.isDragging()) { - if (isSmall()) { + if (workspaceInModalState()) { // If we are in springloaded mode, then force an event to check if the current touch // is under a new page (to scroll to) mDragController.forceTouchMove(); @@ -1215,7 +1259,7 @@ public class Workspace extends SmoothPagedView if (hasCustomContent() && getNextPage() == 0 && !mCustomContentShowing) { mCustomContentShowing = true; if (mCustomContentCallbacks != null) { - mCustomContentCallbacks.onShow(); + mCustomContentCallbacks.onShow(false); mCustomContentShowTime = System.currentTimeMillis(); mLauncher.updateVoiceButtonProxyVisible(false); } @@ -1227,9 +1271,6 @@ public class Workspace extends SmoothPagedView mLauncher.updateVoiceButtonProxyVisible(false); } } - if (getPageIndicator() != null) { - getPageIndicator().setContentDescription(getPageIndicatorDescription()); - } } protected CustomContentCallbacks getCustomContentCallbacks() { @@ -1243,7 +1284,8 @@ public class Workspace extends SmoothPagedView SharedPreferences sp = mLauncher.getSharedPreferences(spKey, Context.MODE_MULTI_PROCESS); LauncherWallpaperPickerActivity.suggestWallpaperDimension(mLauncher.getResources(), - sp, mLauncher.getWindowManager(), mWallpaperManager); + sp, mLauncher.getWindowManager(), mWallpaperManager, + mLauncher.overrideWallpaperDimensions()); return null; } }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void) null); @@ -1261,6 +1303,10 @@ public class Workspace extends SmoothPagedView snapToPage(whichPage, duration); } + public void snapToScreenId(long screenId) { + snapToScreenId(screenId, null); + } + protected void snapToScreenId(long screenId, Runnable r) { snapToPage(getPageIndexForScreenId(screenId), r); } @@ -1445,8 +1491,16 @@ public class Workspace extends SmoothPagedView mWallpaperOffset.syncWithScroll(); } + @Override + public void announceForAccessibility(CharSequence text) { + // Don't announce if apps is on top of us. + if (!mLauncher.isAllAppsVisible()) { + super.announceForAccessibility(text); + } + } + void showOutlines() { - if (!isSmall() && !mIsSwitchingState) { + if (!workspaceInModalState() && !mIsSwitchingState) { if (mChildrenOutlineFadeOutAnimation != null) mChildrenOutlineFadeOutAnimation.cancel(); if (mChildrenOutlineFadeInAnimation != null) mChildrenOutlineFadeInAnimation.cancel(); mChildrenOutlineFadeInAnimation = LauncherAnimUtils.ofFloat(this, "childrenOutlineAlpha", 1.0f); @@ -1456,7 +1510,7 @@ public class Workspace extends SmoothPagedView } void hideOutlines() { - if (!isSmall() && !mIsSwitchingState) { + if (!workspaceInModalState() && !mIsSwitchingState) { if (mChildrenOutlineFadeInAnimation != null) mChildrenOutlineFadeInAnimation.cancel(); if (mChildrenOutlineFadeOutAnimation != null) mChildrenOutlineFadeOutAnimation.cancel(); mChildrenOutlineFadeOutAnimation = LauncherAnimUtils.ofFloat(this, "childrenOutlineAlpha", 0.0f); @@ -1484,15 +1538,9 @@ public class Workspace extends SmoothPagedView return mChildrenOutlineAlpha; } - void disableBackground() { - mDrawBackground = false; - } - void enableBackground() { - mDrawBackground = true; - } - private void animateBackgroundGradient(float finalAlpha, boolean animated) { - if (mBackground == null) return; + final DragLayer dragLayer = mLauncher.getDragLayer(); + if (mBackgroundFadeInAnimation != null) { mBackgroundFadeInAnimation.cancel(); mBackgroundFadeInAnimation = null; @@ -1501,36 +1549,26 @@ public class Workspace extends SmoothPagedView mBackgroundFadeOutAnimation.cancel(); mBackgroundFadeOutAnimation = null; } - float startAlpha = getBackgroundAlpha(); + float startAlpha = dragLayer.getBackgroundAlpha(); if (finalAlpha != startAlpha) { if (animated) { mBackgroundFadeOutAnimation = LauncherAnimUtils.ofFloat(this, startAlpha, finalAlpha); mBackgroundFadeOutAnimation.addUpdateListener(new AnimatorUpdateListener() { public void onAnimationUpdate(ValueAnimator animation) { - setBackgroundAlpha(((Float) animation.getAnimatedValue()).floatValue()); + dragLayer.setBackgroundAlpha( + ((Float)animation.getAnimatedValue()).floatValue()); } }); mBackgroundFadeOutAnimation.setInterpolator(new DecelerateInterpolator(1.5f)); mBackgroundFadeOutAnimation.setDuration(BACKGROUND_FADE_OUT_DURATION); mBackgroundFadeOutAnimation.start(); } else { - setBackgroundAlpha(finalAlpha); + dragLayer.setBackgroundAlpha(finalAlpha); } } } - public void setBackgroundAlpha(float alpha) { - if (alpha != mBackgroundAlpha) { - mBackgroundAlpha = alpha; - invalidate(); - } - } - - public float getBackgroundAlpha() { - return mBackgroundAlpha; - } - float backgroundAlphaInterpolator(float r) { float pivotA = 0.1f; float pivotB = 0.4f; @@ -1546,7 +1584,7 @@ public class Workspace extends SmoothPagedView private void updatePageAlphaValues(int screenCenter) { boolean isInOverscroll = mOverScrollX < 0 || mOverScrollX > mMaxScrollX; if (mWorkspaceFadeInAdjacentScreens && - mState == State.NORMAL && + !workspaceInModalState() && !mIsSwitchingState && !isInOverscroll) { for (int i = numCustomPages(); i < getChildCount(); i++) { @@ -1555,6 +1593,7 @@ public class Workspace extends SmoothPagedView float scrollProgress = getScrollProgress(screenCenter, child, i); float alpha = 1 - Math.abs(scrollProgress); child.getShortcutsAndWidgets().setAlpha(alpha); + //child.setBackgroundAlphaMultiplier(1 - alpha); } } } @@ -1602,13 +1641,13 @@ public class Workspace extends SmoothPagedView if (Float.compare(progress, mLastCustomContentScrollProgress) == 0) return; CellLayout cc = mWorkspaceScreens.get(CUSTOM_CONTENT_SCREEN_ID); - if (progress > 0 && cc.getVisibility() != VISIBLE && !isSmall()) { + if (progress > 0 && cc.getVisibility() != VISIBLE && !workspaceInModalState()) { cc.setVisibility(VISIBLE); } mLastCustomContentScrollProgress = progress; - setBackgroundAlpha(progress * 0.8f); + mLauncher.getDragLayer().setBackgroundAlpha(progress * 0.8f); if (mLauncher.getHotseat() != null) { mLauncher.getHotseat().setTranslationX(translationX); @@ -1648,47 +1687,40 @@ public class Workspace extends SmoothPagedView updateStateForCustomContent(screenCenter); enableHwLayersOnVisiblePages(); - boolean shouldOverScroll = (mOverScrollX < 0 && (!hasCustomContent() || isLayoutRtl())) || - (mOverScrollX > mMaxScrollX && (!hasCustomContent() || !isLayoutRtl())); + boolean shouldOverScroll = mOverScrollX < 0 || mOverScrollX > mMaxScrollX; if (shouldOverScroll) { int index = 0; - float pivotX = 0f; - final float leftBiasedPivot = 0.25f; - final float rightBiasedPivot = 0.75f; final int lowerIndex = 0; final int upperIndex = getChildCount() - 1; final boolean isLeftPage = mOverScrollX < 0; index = (!isRtl && isLeftPage) || (isRtl && !isLeftPage) ? lowerIndex : upperIndex; - pivotX = isLeftPage ? rightBiasedPivot : leftBiasedPivot; CellLayout cl = (CellLayout) getChildAt(index); - float scrollProgress = getScrollProgress(screenCenter, cl, index); - cl.setOverScrollAmount(Math.abs(scrollProgress), isLeftPage); - float rotation = -WORKSPACE_OVERSCROLL_ROTATION * scrollProgress; - cl.setRotationY(rotation); - - if (!mOverscrollTransformsSet || Float.compare(mLastOverscrollPivotX, pivotX) != 0) { - mOverscrollTransformsSet = true; - mLastOverscrollPivotX = pivotX; - cl.setCameraDistance(mDensity * mCameraDistance); - cl.setPivotX(cl.getMeasuredWidth() * pivotX); - cl.setPivotY(cl.getMeasuredHeight() * 0.5f); - cl.setOverscrollTransformsDirty(true); - } + float effect = Math.abs(mOverScrollEffect); + cl.setOverScrollAmount(Math.abs(effect), isLeftPage); + + mOverscrollEffectSet = true; } else { - if (mOverscrollTransformsSet && getChildCount() > 0) { - mOverscrollTransformsSet = false; - ((CellLayout) getChildAt(0)).resetOverscrollTransforms(); - ((CellLayout) getChildAt(getChildCount() - 1)).resetOverscrollTransforms(); + if (mOverscrollEffectSet && getChildCount() > 0) { + mOverscrollEffectSet = false; + ((CellLayout) getChildAt(0)).setOverScrollAmount(0, false); + ((CellLayout) getChildAt(getChildCount() - 1)).setOverScrollAmount(0, false); } } } @Override protected void overScroll(float amount) { - acceleratedOverScroll(amount); + boolean shouldOverScroll = (amount < 0 && (!hasCustomContent() || isLayoutRtl())) || + (amount > 0 && (!hasCustomContent() || !isLayoutRtl())); + if (shouldOverScroll) { + dampedOverScroll(amount); + mOverScrollEffect = acceleratedOverFactor(amount); + } else { + mOverScrollEffect = 0; + } } protected void onAttachedToWindow() { @@ -1738,25 +1770,12 @@ public class Workspace extends SmoothPagedView @Override protected void onDraw(Canvas canvas) { - // Draw the background gradient if necessary - if (mBackground != null && mBackgroundAlpha > 0.0f && mDrawBackground) { - int alpha = (int) (mBackgroundAlpha * 255); - mBackground.setAlpha(alpha); - mBackground.setBounds(getScrollX(), 0, getScrollX() + getMeasuredWidth(), - getMeasuredHeight()); - mBackground.draw(canvas); - } - super.onDraw(canvas); // Call back to LauncherModel to finish binding after the first draw post(mBindPages); } - boolean isDrawingBackgroundGradient() { - return (mBackground != null && mBackgroundAlpha > 0.0f && mDrawBackground); - } - @Override protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) { if (!mLauncher.isAllAppsVisible()) { @@ -1772,7 +1791,7 @@ public class Workspace extends SmoothPagedView @Override public int getDescendantFocusability() { - if (isSmall()) { + if (workspaceInModalState()) { return ViewGroup.FOCUS_BLOCK_DESCENDANTS; } return super.getDescendantFocusability(); @@ -1790,8 +1809,8 @@ public class Workspace extends SmoothPagedView } } - public boolean isSmall() { - return mState == State.SMALL || mState == State.SPRING_LOADED || mState == State.OVERVIEW; + public boolean workspaceInModalState() { + return mState != State.NORMAL; } void enableChildrenCache(int fromPage, int toPage) { @@ -1826,7 +1845,7 @@ public class Workspace extends SmoothPagedView } private void updateChildrenLayersEnabled(boolean force) { - boolean small = mState == State.SMALL || mState == State.OVERVIEW || mIsSwitchingState; + boolean small = mState == State.OVERVIEW || mIsSwitchingState; boolean enableChildrenLayers = force || small || mAnimatingViewIntoPlace || isPageMoving(); if (enableChildrenLayers != mChildrenLayersEnabled) { @@ -1964,21 +1983,54 @@ public class Workspace extends SmoothPagedView * appearance). * */ - public void onDragStartedWithItem(View v) { - final Canvas canvas = new Canvas(); + private static Rect getDrawableBounds(Drawable d) { + Rect bounds = new Rect(); + d.copyBounds(bounds); + if (bounds.width() == 0 || bounds.height() == 0) { + bounds.set(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight()); + } else { + bounds.offsetTo(0, 0); + } + if (d instanceof PreloadIconDrawable) { + int inset = -((PreloadIconDrawable) d).getOutset(); + bounds.inset(inset, inset); + } + return bounds; + } + + public void onExternalDragStartedWithItem(View v) { + // Compose a drag bitmap with the view scaled to the icon size + LauncherAppState app = LauncherAppState.getInstance(); + DeviceProfile grid = app.getDynamicGrid().getDeviceProfile(); + int iconSize = grid.iconSizePx; + int bmpWidth = v.getMeasuredWidth(); + int bmpHeight = v.getMeasuredHeight(); + + // If this is a text view, use its drawable instead + if (v instanceof TextView) { + TextView tv = (TextView) v; + Drawable d = tv.getCompoundDrawables()[1]; + Rect bounds = getDrawableBounds(d); + bmpWidth = bounds.width(); + bmpHeight = bounds.height(); + } + + // Compose the bitmap to create the icon from + Bitmap b = Bitmap.createBitmap(bmpWidth, bmpHeight, + Bitmap.Config.ARGB_8888); + mCanvas.setBitmap(b); + drawDragView(v, mCanvas, 0); + mCanvas.setBitmap(null); // The outline is used to visualize where the item will land if dropped - mDragOutline = createDragOutline(v, canvas, DRAG_BITMAP_PADDING); + mDragOutline = createDragOutline(b, DRAG_BITMAP_PADDING, iconSize, iconSize, true); } public void onDragStartedWithItem(PendingAddItemInfo info, Bitmap b, boolean clipAlpha) { - final Canvas canvas = new Canvas(); - int[] size = estimateItemSize(info.spanX, info.spanY, info, false); // The outline is used to visualize where the item will land if dropped - mDragOutline = createDragOutline(b, canvas, DRAG_BITMAP_PADDING, size[0], - size[1], clipAlpha); + mDragOutline = createDragOutline(b, DRAG_BITMAP_PADDING, size[0], size[1], clipAlpha); } public void exitWidgetResizeMode() { @@ -1996,18 +2048,23 @@ public class Workspace extends SmoothPagedView mNewAlphas = new float[childCount]; } - Animator getChangeStateAnimation(final State state, boolean animated) { - return getChangeStateAnimation(state, animated, 0, -1); + Animator getChangeStateAnimation(final State state, boolean animated, + ArrayList<View> layerViews) { + return getChangeStateAnimation(state, animated, 0, -1, layerViews); } @Override - protected void getOverviewModePages(int[] range) { + protected void getFreeScrollPageRange(int[] range) { + getOverviewModePages(range); + } + + private void getOverviewModePages(int[] range) { int start = numCustomPages(); int end = getChildCount() - 1; range[0] = Math.max(0, Math.min(start, getChildCount() - 1)); range[1] = Math.max(0, end); - } + } protected void onStartReordering() { super.onStartReordering(); @@ -2019,6 +2076,11 @@ public class Workspace extends SmoothPagedView protected void onEndReordering() { super.onEndReordering(); + if (mLauncher.isWorkspaceLoading()) { + // Invalid and dangerous operation if workspace is loading + return; + } + hideOutlines(); mScreenOrder.clear(); int count = getChildCount(); @@ -2110,6 +2172,10 @@ public class Workspace extends SmoothPagedView updateAccessibilityFlags(); } + State getState() { + return mState; + } + private void updateAccessibilityFlags() { int accessible = mState == State.NORMAL ? ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES : @@ -2117,7 +2183,14 @@ public class Workspace extends SmoothPagedView setImportantForAccessibility(accessible); } + private static final int HIDE_WORKSPACE_DURATION = 100; + Animator getChangeStateAnimation(final State state, boolean animated, int delay, int snapPage) { + return getChangeStateAnimation(state, animated, delay, snapPage, null); + } + + Animator getChangeStateAnimation(final State state, boolean animated, int delay, int snapPage, + ArrayList<View> layerViews) { if (mState == state) { return null; } @@ -2130,21 +2203,25 @@ public class Workspace extends SmoothPagedView final State oldState = mState; final boolean oldStateIsNormal = (oldState == State.NORMAL); final boolean oldStateIsSpringLoaded = (oldState == State.SPRING_LOADED); - final boolean oldStateIsSmall = (oldState == State.SMALL); + final boolean oldStateIsNormalHidden = (oldState == State.NORMAL_HIDDEN); + final boolean oldStateIsOverviewHidden = (oldState == State.OVERVIEW_HIDDEN); final boolean oldStateIsOverview = (oldState == State.OVERVIEW); setState(state); final boolean stateIsNormal = (state == State.NORMAL); final boolean stateIsSpringLoaded = (state == State.SPRING_LOADED); - final boolean stateIsSmall = (state == State.SMALL); + final boolean stateIsNormalHidden = (state == State.NORMAL_HIDDEN); + final boolean stateIsOverviewHidden = (state == State.OVERVIEW_HIDDEN); final boolean stateIsOverview = (state == State.OVERVIEW); float finalBackgroundAlpha = (stateIsSpringLoaded || stateIsOverview) ? 1.0f : 0f; - float finalHotseatAndPageIndicatorAlpha = (stateIsOverview || stateIsSmall) ? 0f : 1f; + float finalHotseatAndPageIndicatorAlpha = (stateIsNormal || stateIsSpringLoaded) ? 1f : 0f; float finalOverviewPanelAlpha = stateIsOverview ? 1f : 0f; float finalSearchBarAlpha = !stateIsNormal ? 0f : 1f; - float finalWorkspaceTranslationY = stateIsOverview ? getOverviewModeTranslationY() : 0; + float finalWorkspaceTranslationY = stateIsOverview || stateIsOverviewHidden ? + getOverviewModeTranslationY() : 0; - boolean workspaceToAllApps = (oldStateIsNormal && stateIsSmall); - boolean allAppsToWorkspace = (oldStateIsSmall && stateIsNormal); + boolean workspaceToAllApps = (oldStateIsNormal && stateIsNormalHidden); + boolean overviewToAllApps = (oldStateIsOverview && stateIsOverviewHidden); + boolean allAppsToWorkspace = (stateIsNormalHidden && stateIsNormal); boolean workspaceToOverview = (oldStateIsNormal && stateIsOverview); boolean overviewToWorkspace = (oldStateIsOverview && stateIsNormal); @@ -2159,19 +2236,14 @@ public class Workspace extends SmoothPagedView if (state != State.NORMAL) { if (stateIsSpringLoaded) { mNewScale = mSpringLoadedShrinkFactor; - } else if (stateIsOverview) { + } else if (stateIsOverview || stateIsOverviewHidden) { mNewScale = mOverviewModeShrinkFactor; - } else if (stateIsSmall){ - mNewScale = mOverviewModeShrinkFactor - 0.3f; - } - if (workspaceToAllApps) { - updateChildrenLayersEnabled(false); } } final int duration; - if (workspaceToAllApps) { - duration = getResources().getInteger(R.integer.config_workspaceUnshrinkTime); + if (workspaceToAllApps || overviewToAllApps) { + duration = HIDE_WORKSPACE_DURATION; //getResources().getInteger(R.integer.config_workspaceUnshrinkTime); } else if (workspaceToOverview || overviewToWorkspace) { duration = getResources().getInteger(R.integer.config_overviewTransitionTime); } else { @@ -2188,7 +2260,7 @@ public class Workspace extends SmoothPagedView boolean isCurrentPage = (i == snapPage); float initialAlpha = cl.getShortcutsAndWidgets().getAlpha(); float finalAlpha; - if (stateIsSmall) { + if (stateIsNormalHidden || stateIsOverviewHidden) { finalAlpha = 0f; } else if (stateIsNormal && mWorkspaceFadeInAdjacentScreens) { finalAlpha = (i == snapPage || i < numCustomPages()) ? 1f : 0f; @@ -2225,11 +2297,11 @@ public class Workspace extends SmoothPagedView final View hotseat = mLauncher.getHotseat(); final View pageIndicator = getPageIndicator(); if (animated) { - anim.setDuration(duration); LauncherViewPropertyAnimator scale = new LauncherViewPropertyAnimator(this); scale.scaleX(mNewScale) .scaleY(mNewScale) .translationY(finalWorkspaceTranslationY) + .setDuration(duration) .setInterpolator(mZoomInInterpolator); anim.play(scale); for (int index = 0; index < getChildCount(); index++) { @@ -2240,10 +2312,14 @@ public class Workspace extends SmoothPagedView cl.setBackgroundAlpha(mNewBackgroundAlphas[i]); cl.setShortcutAndWidgetAlpha(mNewAlphas[i]); } else { + if (layerViews != null) { + layerViews.add(cl); + } if (mOldAlphas[i] != mNewAlphas[i] || currentAlpha != mNewAlphas[i]) { LauncherViewPropertyAnimator alphaAnim = new LauncherViewPropertyAnimator(cl.getShortcutsAndWidgets()); alphaAnim.alpha(mNewAlphas[i]) + .setDuration(duration) .setInterpolator(mZoomInInterpolator); anim.play(alphaAnim); } @@ -2252,6 +2328,7 @@ public class Workspace extends SmoothPagedView ValueAnimator bgAnim = LauncherAnimUtils.ofFloat(cl, 0f, 1f); bgAnim.setInterpolator(mZoomInInterpolator); + bgAnim.setDuration(duration); bgAnim.addUpdateListener(new LauncherAnimatorUpdateListener() { public void onAnimationUpdate(float a, float b) { cl.setBackgroundAlpha( @@ -2285,6 +2362,17 @@ public class Workspace extends SmoothPagedView .alpha(finalOverviewPanelAlpha).withLayer(); overviewPanelAlpha.addListener(new AlphaUpdateListener(overviewPanel)); + // For animation optimations, we may need to provide the Launcher transition + // with a set of views on which to force build layers in certain scenarios. + hotseat.setLayerType(View.LAYER_TYPE_HARDWARE, null); + searchBar.setLayerType(View.LAYER_TYPE_HARDWARE, null); + overviewPanel.setLayerType(View.LAYER_TYPE_HARDWARE, null); + if (layerViews != null) { + layerViews.add(hotseat); + layerViews.add(searchBar); + layerViews.add(overviewPanel); + } + if (workspaceToOverview) { pageIndicatorAlpha.setInterpolator(new DecelerateInterpolator(2)); hotseatAlpha.setInterpolator(new DecelerateInterpolator(2)); @@ -2294,7 +2382,11 @@ public class Workspace extends SmoothPagedView hotseatAlpha.setInterpolator(null); overviewPanelAlpha.setInterpolator(new DecelerateInterpolator(2)); } - searchBarAlpha.setInterpolator(null); + + overviewPanelAlpha.setDuration(duration); + pageIndicatorAlpha.setDuration(duration); + hotseatAlpha.setDuration(duration); + searchBarAlpha.setDuration(duration); anim.play(overviewPanelAlpha); anim.play(hotseatAlpha); @@ -2319,18 +2411,11 @@ public class Workspace extends SmoothPagedView } mLauncher.updateVoiceButtonProxyVisible(false); - if (stateIsSpringLoaded) { - // Right now we're covered by Apps Customize - // Show the background gradient immediately, so the gradient will - // be showing once AppsCustomize disappears - animateBackgroundGradient(getResources().getInteger( - R.integer.config_appsCustomizeSpringLoadedBgAlpha) / 100f, false); - } else if (stateIsOverview) { - animateBackgroundGradient(getResources().getInteger( - R.integer.config_appsCustomizeSpringLoadedBgAlpha) / 100f, true); - } else { - // Fade the background gradient away + if (stateIsNormal) { animateBackgroundGradient(0f, animated); + } else { + animateBackgroundGradient(getResources().getInteger( + R.integer.config_workspaceScrimAlpha) / 100f, animated); } return anim; } @@ -2433,21 +2518,6 @@ public class Workspace extends SmoothPagedView private void onTransitionEnd() { mIsSwitchingState = false; updateChildrenLayersEnabled(false); - // The code in getChangeStateAnimation to determine initialAlpha and finalAlpha will ensure - // ensure that only the current page is visible during (and subsequently, after) the - // transition animation. If fade adjacent pages is disabled, then re-enable the page - // visibility after the transition animation. - if (!mWorkspaceFadeInAdjacentScreens) { - for (int i = 0; i < getChildCount(); i++) { - final CellLayout cl = (CellLayout) getChildAt(i); - cl.setShortcutAndWidgetAlpha(1f); - } - } else { - for (int i = 0; i < numCustomPages(); i++) { - final CellLayout cl = (CellLayout) getChildAt(i); - cl.setShortcutAndWidgetAlpha(1f); - } - } showCustomContentIfNecessary(); } @@ -2463,17 +2533,18 @@ public class Workspace extends SmoothPagedView * @param destCanvas the canvas to draw on * @param padding the horizontal and vertical padding to use when drawing */ - private void drawDragView(View v, Canvas destCanvas, int padding, boolean pruneToDrawable) { - final Rect clipRect = mTempRect; + private static void drawDragView(View v, Canvas destCanvas, int padding) { + final Rect clipRect = sTempRect; v.getDrawingRect(clipRect); boolean textVisible = false; destCanvas.save(); - if (v instanceof TextView && pruneToDrawable) { + if (v instanceof TextView) { Drawable d = ((TextView) v).getCompoundDrawables()[1]; - clipRect.set(0, 0, d.getIntrinsicWidth() + padding, d.getIntrinsicHeight() + padding); - destCanvas.translate(padding / 2, padding / 2); + Rect bounds = getDrawableBounds(d); + clipRect.set(0, 0, bounds.width() + padding, bounds.height() + padding); + destCanvas.translate(padding / 2 - bounds.left, padding / 2 - bounds.top); d.draw(destCanvas); } else { if (v instanceof FolderIcon) { @@ -2483,14 +2554,6 @@ public class Workspace extends SmoothPagedView ((FolderIcon) v).setTextVisible(false); textVisible = true; } - } else if (v instanceof BubbleTextView) { - final BubbleTextView tv = (BubbleTextView) v; - clipRect.bottom = tv.getExtendedPaddingTop() - (int) BubbleTextView.PADDING_V + - tv.getLayout().getLineTop(0); - } else if (v instanceof TextView) { - final TextView tv = (TextView) v; - clipRect.bottom = tv.getExtendedPaddingTop() - tv.getCompoundDrawablePadding() + - tv.getLayout().getLineTop(0); } destCanvas.translate(-v.getScrollX() + padding / 2, -v.getScrollY() + padding / 2); destCanvas.clipRect(clipRect, Op.REPLACE); @@ -2507,22 +2570,27 @@ public class Workspace extends SmoothPagedView /** * Returns a new bitmap to show when the given View is being dragged around. * Responsibility for the bitmap is transferred to the caller. + * @param expectedPadding padding to add to the drag view. If a different padding was used + * its value will be changed */ - public Bitmap createDragBitmap(View v, Canvas canvas, int padding) { + public Bitmap createDragBitmap(View v, AtomicInteger expectedPadding) { Bitmap b; + int padding = expectedPadding.get(); if (v instanceof TextView) { Drawable d = ((TextView) v).getCompoundDrawables()[1]; - b = Bitmap.createBitmap(d.getIntrinsicWidth() + padding, - d.getIntrinsicHeight() + padding, Bitmap.Config.ARGB_8888); + Rect bounds = getDrawableBounds(d); + b = Bitmap.createBitmap(bounds.width() + padding, + bounds.height() + padding, Bitmap.Config.ARGB_8888); + expectedPadding.set(padding - bounds.left - bounds.top); } else { b = Bitmap.createBitmap( v.getWidth() + padding, v.getHeight() + padding, Bitmap.Config.ARGB_8888); } - canvas.setBitmap(b); - drawDragView(v, canvas, padding, true); - canvas.setBitmap(null); + mCanvas.setBitmap(b); + drawDragView(v, mCanvas, padding); + mCanvas.setBitmap(null); return b; } @@ -2531,15 +2599,15 @@ public class Workspace extends SmoothPagedView * Returns a new bitmap to be used as the object outline, e.g. to visualize the drop location. * Responsibility for the bitmap is transferred to the caller. */ - private Bitmap createDragOutline(View v, Canvas canvas, int padding) { + private Bitmap createDragOutline(View v, int padding) { final int outlineColor = getResources().getColor(R.color.outline_color); final Bitmap b = Bitmap.createBitmap( v.getWidth() + padding, v.getHeight() + padding, Bitmap.Config.ARGB_8888); - canvas.setBitmap(b); - drawDragView(v, canvas, padding, true); - mOutlineHelper.applyMediumExpensiveOutlineWithBlur(b, canvas, outlineColor, outlineColor); - canvas.setBitmap(null); + mCanvas.setBitmap(b); + drawDragView(v, mCanvas, padding); + mOutlineHelper.applyExpensiveOutlineWithBlur(b, mCanvas, outlineColor, outlineColor); + mCanvas.setBitmap(null); return b; } @@ -2547,11 +2615,11 @@ public class Workspace extends SmoothPagedView * Returns a new bitmap to be used as the object outline, e.g. to visualize the drop location. * Responsibility for the bitmap is transferred to the caller. */ - private Bitmap createDragOutline(Bitmap orig, Canvas canvas, int padding, int w, int h, + private Bitmap createDragOutline(Bitmap orig, int padding, int w, int h, boolean clipAlpha) { final int outlineColor = getResources().getColor(R.color.outline_color); final Bitmap b = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); - canvas.setBitmap(b); + mCanvas.setBitmap(b); Rect src = new Rect(0, 0, orig.getWidth(), orig.getHeight()); float scaleFactor = Math.min((w - padding) / (float) orig.getWidth(), @@ -2563,10 +2631,10 @@ public class Workspace extends SmoothPagedView // center the image dst.offset((w - scaledWidth) / 2, (h - scaledHeight) / 2); - canvas.drawBitmap(orig, src, dst, null); - mOutlineHelper.applyMediumExpensiveOutlineWithBlur(b, canvas, outlineColor, outlineColor, + mCanvas.drawBitmap(orig, src, dst, null); + mOutlineHelper.applyExpensiveOutlineWithBlur(b, mCanvas, outlineColor, outlineColor, clipAlpha); - canvas.setBitmap(null); + mCanvas.setBitmap(null); return b; } @@ -2584,35 +2652,34 @@ public class Workspace extends SmoothPagedView CellLayout layout = (CellLayout) child.getParent().getParent(); layout.prepareChildForDrag(child); + beginDragShared(child, this); + } + + public void beginDragShared(View child, DragSource source) { child.clearFocus(); child.setPressed(false); - final Canvas canvas = new Canvas(); - // The outline is used to visualize where the item will land if dropped - mDragOutline = createDragOutline(child, canvas, DRAG_BITMAP_PADDING); - beginDragShared(child, this); - } + mDragOutline = createDragOutline(child, DRAG_BITMAP_PADDING); - public void beginDragShared(View child, DragSource source) { + mLauncher.onDragStarted(child); // The drag bitmap follows the touch point around on the screen - final Bitmap b = createDragBitmap(child, new Canvas(), DRAG_BITMAP_PADDING); + AtomicInteger padding = new AtomicInteger(DRAG_BITMAP_PADDING); + final Bitmap b = createDragBitmap(child, padding); final int bmpWidth = b.getWidth(); final int bmpHeight = b.getHeight(); float scale = mLauncher.getDragLayer().getLocationInDragLayer(child, mTempXY); - int dragLayerX = - Math.round(mTempXY[0] - (bmpWidth - scale * child.getWidth()) / 2); - int dragLayerY = - Math.round(mTempXY[1] - (bmpHeight - scale * bmpHeight) / 2 - - DRAG_BITMAP_PADDING / 2); + int dragLayerX = Math.round(mTempXY[0] - (bmpWidth - scale * child.getWidth()) / 2); + int dragLayerY = Math.round(mTempXY[1] - (bmpHeight - scale * bmpHeight) / 2 + - padding.get() / 2); LauncherAppState app = LauncherAppState.getInstance(); DeviceProfile grid = app.getDynamicGrid().getDeviceProfile(); Point dragVisualizeOffset = null; Rect dragRect = null; - if (child instanceof BubbleTextView || child instanceof PagedViewIcon) { + if (child instanceof BubbleTextView) { int iconSize = grid.iconSizePx; int top = child.getPaddingTop(); int left = (bmpWidth - iconSize) / 2; @@ -2621,7 +2688,7 @@ public class Workspace extends SmoothPagedView dragLayerY += top; // Note: The drag region is used to calculate drag layer offsets, but the // dragVisualizeOffset in addition to the dragRect (the size) to position the outline. - dragVisualizeOffset = new Point(-DRAG_BITMAP_PADDING / 2, DRAG_BITMAP_PADDING / 2); + dragVisualizeOffset = new Point(-padding.get() / 2, padding.get() / 2); dragRect = new Rect(left, top, right, bottom); } else if (child instanceof FolderIcon) { int previewSize = grid.folderIconSizePx; @@ -2631,10 +2698,7 @@ public class Workspace extends SmoothPagedView // Clear the pressed state if necessary if (child instanceof BubbleTextView) { BubbleTextView icon = (BubbleTextView) child; - icon.clearPressedOrFocusedBackground(); - } else if (child instanceof FolderIcon) { - // Dismiss the folder cling if we haven't already - mLauncher.getLauncherClings().markFolderClingDismissed(); + icon.clearPressedBackground(); } if (child.getTag() == null || !(child.getTag() instanceof ItemInfo)) { @@ -2655,6 +2719,53 @@ public class Workspace extends SmoothPagedView b.recycle(); } + public void beginExternalDragShared(View child, DragSource source) { + LauncherAppState app = LauncherAppState.getInstance(); + DeviceProfile grid = app.getDynamicGrid().getDeviceProfile(); + int iconSize = grid.iconSizePx; + + // Notify launcher of drag start + mLauncher.onDragStarted(child); + + // Compose a new drag bitmap that is of the icon size + AtomicInteger padding = new AtomicInteger(DRAG_BITMAP_PADDING); + final Bitmap tmpB = createDragBitmap(child, padding); + Bitmap b = Bitmap.createBitmap(iconSize, iconSize, Bitmap.Config.ARGB_8888); + Paint p = new Paint(); + p.setFilterBitmap(true); + mCanvas.setBitmap(b); + mCanvas.drawBitmap(tmpB, new Rect(0, 0, tmpB.getWidth(), tmpB.getHeight()), + new Rect(0, 0, iconSize, iconSize), p); + mCanvas.setBitmap(null); + + // Find the child's location on the screen + int bmpWidth = tmpB.getWidth(); + float iconScale = (float) bmpWidth / iconSize; + float scale = mLauncher.getDragLayer().getLocationInDragLayer(child, mTempXY) * iconScale; + int dragLayerX = Math.round(mTempXY[0] - (bmpWidth - scale * child.getWidth()) / 2); + int dragLayerY = Math.round(mTempXY[1]); + + // Note: The drag region is used to calculate drag layer offsets, but the + // dragVisualizeOffset in addition to the dragRect (the size) to position the outline. + Point dragVisualizeOffset = new Point(-padding.get() / 2, padding.get() / 2); + Rect dragRect = new Rect(0, 0, iconSize, iconSize); + + if (child.getTag() == null || !(child.getTag() instanceof ItemInfo)) { + String msg = "Drag started with a view that has no tag set. This " + + "will cause a crash (issue 11627249) down the line. " + + "View: " + child + " tag: " + child.getTag(); + throw new IllegalStateException(msg); + } + + // Start the drag + DragView dv = mDragController.startDrag(b, dragLayerX, dragLayerY, source, child.getTag(), + DragController.DRAG_ACTION_MOVE, dragVisualizeOffset, dragRect, scale); + dv.setIntrinsicIconScaleFactor(source.getIntrinsicIconScaleFactor()); + + // Recycle temporary bitmaps + tmpB.recycle(); + } + void addApplicationShortcut(ShortcutInfo info, CellLayout target, long container, long screenId, int cellX, int cellY, boolean insertAtFirst, int intersectX, int intersectY) { View view = mLauncher.createShortcut(R.layout.application, target, (ShortcutInfo) info); @@ -2668,7 +2779,8 @@ public class Workspace extends SmoothPagedView } public boolean transitionStateShouldAllowDrop() { - return ((!isSwitchingState() || mTransitionProgress > 0.5f) && mState != State.SMALL); + return ((!isSwitchingState() || mTransitionProgress > 0.5f) && + (mState == State.NORMAL || mState == State.SPRING_LOADED)); } /** @@ -2934,13 +3046,11 @@ public class Workspace extends SmoothPagedView // cell also contains a shortcut, then create a folder with the two shortcuts. if (!mInScrollArea && createUserFolderIfNecessary(cell, container, dropTargetLayout, mTargetCell, distance, false, d.dragView, null)) { - removeExtraEmptyScreen(true, null, 0, true); return; } if (addToExistingFolderIfNecessary(cell, dropTargetLayout, mTargetCell, distance, d, false)) { - removeExtraEmptyScreen(true, null, 0, true); return; } @@ -2981,7 +3091,12 @@ public class Workspace extends SmoothPagedView final ItemInfo info = (ItemInfo) cell.getTag(); if (hasMovedLayouts) { // Reparent the view - getParentCellLayoutForView(cell).removeView(cell); + CellLayout parentCell = getParentCellLayoutForView(cell); + if (parentCell != null) { + parentCell.removeView(cell); + } else if (LauncherAppState.isDogfoodBuild()) { + throw new NullPointerException("mDragInfo.cell has null parent"); + } addInScreen(cell, container, screenId, mTargetCell[0], mTargetCell[1], info.spanX, info.spanY); } @@ -3046,7 +3161,6 @@ public class Workspace extends SmoothPagedView if (finalResizeRunnable != null) { finalResizeRunnable.run(); } - removeExtraEmptyScreen(true, null, 0, true); } }; mAnimatingViewIntoPlace = true; @@ -3115,10 +3229,8 @@ public class Workspace extends SmoothPagedView setCurrentDropLayout(layout); setCurrentDragOverlappingLayout(layout); - // Because we don't have space in the Phone UI (the CellLayouts run to the edge) we - // don't need to show the outlines - if (LauncherAppState.getInstance().isScreenLarge()) { - showOutlines(); + if (!workspaceInModalState()) { + mLauncher.getDragLayer().showPageHints(); } } @@ -3128,7 +3240,6 @@ public class Workspace extends SmoothPagedView LauncherAppState app = LauncherAppState.getInstance(); DeviceProfile grid = app.getDynamicGrid().getDeviceProfile(); - Resources res = launcher.getResources(); Display display = launcher.getWindowManager().getDefaultDisplay(); Point smallestSize = new Point(); Point largestSize = new Point(); @@ -3194,6 +3305,7 @@ public class Workspace extends SmoothPagedView if (!mIsPageMoving) { hideOutlines(); } + mLauncher.getDragLayer().hidePageHints(); } void setCurrentDropLayout(CellLayout layout) { @@ -3436,11 +3548,17 @@ public class Workspace extends SmoothPagedView public void onDragOver(DragObject d) { // Skip drag over events while we are dragging over side pages - if (mInScrollArea || mIsSwitchingState || mState == State.SMALL) return; + if (mInScrollArea || !transitionStateShouldAllowDrop()) return; Rect r = new Rect(); CellLayout layout = null; ItemInfo item = (ItemInfo) d.dragInfo; + if (item == null) { + if (LauncherAppState.isDogfoodBuild()) { + throw new NullPointerException("DragObject has null info"); + } + return; + } // Ensure that we have proper spans for the item that we are dropping if (item.spanX < 0 || item.spanY < 0) throw new RuntimeException("Improper spans found"); @@ -3449,7 +3567,7 @@ public class Workspace extends SmoothPagedView final View child = (mDragInfo == null) ? null : mDragInfo.cell; // Identify whether we have dragged over a side page - if (isSmall()) { + if (workspaceInModalState()) { if (mLauncher.getHotseat() != null && !isExternalDragWidget(d)) { if (isPointInSelfOverHotseat(d.x, d.y, r)) { layout = mLauncher.getHotseat().getLayout(); @@ -3700,13 +3818,8 @@ public class Workspace extends SmoothPagedView final Runnable exitSpringLoadedRunnable = new Runnable() { @Override public void run() { - removeExtraEmptyScreen(false, new Runnable() { - @Override - public void run() { - mLauncher.exitSpringLoadedDragModeDelayed(true, - Launcher.EXIT_SPRINGLOADED_MODE_SHORT_TIMEOUT, null); - } - }); + mLauncher.exitSpringLoadedDragModeDelayed(true, + Launcher.EXIT_SPRINGLOADED_MODE_SHORT_TIMEOUT, null); } }; @@ -3768,6 +3881,11 @@ public class Workspace extends SmoothPagedView Runnable onAnimationCompleteRunnable = new Runnable() { @Override public void run() { + // Normally removeExtraEmptyScreen is called in Workspace#onDragEnd, but when + // adding an item that may not be dropped right away (due to a config activity) + // we defer the removal until the activity returns. + deferRemoveExtraEmptyScreen(); + // When dragging and dropping from customization tray, we deal with creating // widgets/shortcuts/folders in a slightly different way switch (pendingInfo.itemType) { @@ -3852,15 +3970,16 @@ public class Workspace extends SmoothPagedView } else { cellLayout.findCellForSpan(mTargetCell, 1, 1); } + // Add the item to DB before adding to screen ensures that the container and other + // values of the info is properly updated. + LauncherModel.addOrMoveItemInDatabase(mLauncher, info, container, screenId, + mTargetCell[0], mTargetCell[1]); + addInScreen(view, container, screenId, mTargetCell[0], mTargetCell[1], info.spanX, info.spanY, insertAtFirst); cellLayout.onDropChild(view); - CellLayout.LayoutParams lp = (CellLayout.LayoutParams) view.getLayoutParams(); cellLayout.getShortcutsAndWidgets().measureChild(view); - LauncherModel.addOrMoveItemInDatabase(mLauncher, info, container, screenId, - lp.cellX, lp.cellY); - if (d.dragView != null) { // We wrap the animation call in the temporary set and reset of the current // cellLayout to its final transform -- this means we animate the drag view to @@ -3883,12 +4002,12 @@ public class Workspace extends SmoothPagedView int height = MeasureSpec.makeMeasureSpec(unScaledSize[1], MeasureSpec.EXACTLY); Bitmap b = Bitmap.createBitmap(unScaledSize[0], unScaledSize[1], Bitmap.Config.ARGB_8888); - Canvas c = new Canvas(b); + mCanvas.setBitmap(b); layout.measure(width, height); layout.layout(0, 0, unScaledSize[0], unScaledSize[1]); - layout.draw(c); - c.setBitmap(null); + layout.draw(mCanvas); + mCanvas.setBitmap(null); layout.setVisibility(visibility); return b; } @@ -4064,14 +4183,12 @@ public class Workspace extends SmoothPagedView CellLayout parentCell = getParentCellLayoutForView(mDragInfo.cell); if (parentCell != null) { parentCell.removeView(mDragInfo.cell); + } else if (LauncherAppState.isDogfoodBuild()) { + throw new NullPointerException("mDragInfo.cell has null parent"); } if (mDragInfo.cell instanceof DropTarget) { mDragController.removeDropTarget((DropTarget) mDragInfo.cell); } - // If we move the item to anything not on the Workspace, check if any empty - // screens need to be removed. If we dropped back on the workspace, this will - // be done post drop animation. - removeExtraEmptyScreen(true, null, 0, true); } } else if (mDragInfo != null) { CellLayout cellLayout; @@ -4327,7 +4444,7 @@ public class Workspace extends SmoothPagedView @Override public void scrollLeft() { - if (!isSmall() && !mIsSwitchingState) { + if (!workspaceInModalState() && !mIsSwitchingState) { super.scrollLeft(); } Folder openFolder = getOpenFolder(); @@ -4338,7 +4455,7 @@ public class Workspace extends SmoothPagedView @Override public void scrollRight() { - if (!isSmall() && !mIsSwitchingState) { + if (!workspaceInModalState() && !mIsSwitchingState) { super.scrollRight(); } Folder openFolder = getOpenFolder(); @@ -4360,7 +4477,7 @@ public class Workspace extends SmoothPagedView } boolean result = false; - if (!isSmall() && !mIsSwitchingState && getOpenFolder() == null) { + if (!workspaceInModalState() && !mIsSwitchingState && getOpenFolder() == null) { mInScrollArea = true; final int page = getNextPage() + @@ -4452,57 +4569,70 @@ public class Workspace extends SmoothPagedView return childrenLayouts; } - public Folder getFolderForTag(Object tag) { - ArrayList<ShortcutAndWidgetContainer> childrenLayouts = - getAllShortcutAndWidgetContainers(); - for (ShortcutAndWidgetContainer layout: childrenLayouts) { - int count = layout.getChildCount(); - for (int i = 0; i < count; i++) { - View child = layout.getChildAt(i); - if (child instanceof Folder) { - Folder f = (Folder) child; - if (f.getInfo() == tag && f.getInfo().opened) { - return f; - } - } + public Folder getFolderForTag(final Object tag) { + return (Folder) getFirstMatch(new ItemOperator() { + + @Override + public boolean evaluate(ItemInfo info, View v, View parent) { + return (v instanceof Folder) && (((Folder) v).getInfo() == tag) + && ((Folder) v).getInfo().opened; } - } - return null; + }); } - public View getViewForTag(Object tag) { - ArrayList<ShortcutAndWidgetContainer> childrenLayouts = - getAllShortcutAndWidgetContainers(); - for (ShortcutAndWidgetContainer layout: childrenLayouts) { - int count = layout.getChildCount(); - for (int i = 0; i < count; i++) { - View child = layout.getChildAt(i); - if (child.getTag() == tag) { - return child; + public View getViewForTag(final Object tag) { + return getFirstMatch(new ItemOperator() { + + @Override + public boolean evaluate(ItemInfo info, View v, View parent) { + return info == tag; + } + }); + } + + public LauncherAppWidgetHostView getWidgetForAppWidgetId(final int appWidgetId) { + return (LauncherAppWidgetHostView) getFirstMatch(new ItemOperator() { + + @Override + public boolean evaluate(ItemInfo info, View v, View parent) { + return (info instanceof LauncherAppWidgetInfo) && + ((LauncherAppWidgetInfo) info).appWidgetId == appWidgetId; + } + }); + } + + private View getFirstMatch(final ItemOperator operator) { + final View[] value = new View[1]; + mapOverItems(MAP_NO_RECURSE, new ItemOperator() { + @Override + public boolean evaluate(ItemInfo info, View v, View parent) { + if (operator.evaluate(info, v, parent)) { + value[0] = v; + return true; } + return false; } - } - return null; + }); + return value[0]; } void clearDropTargets() { - ArrayList<ShortcutAndWidgetContainer> childrenLayouts = - getAllShortcutAndWidgetContainers(); - for (ShortcutAndWidgetContainer layout: childrenLayouts) { - int childCount = layout.getChildCount(); - for (int j = 0; j < childCount; j++) { - View v = layout.getChildAt(j); + mapOverItems(MAP_NO_RECURSE, new ItemOperator() { + @Override + public boolean evaluate(ItemInfo info, View v, View parent) { if (v instanceof DropTarget) { mDragController.removeDropTarget((DropTarget) v); } + // not done, process all the shortcuts + return false; } - } + }); } // Removes ALL items that match a given package name, this is usually called when a package // has been removed and we want to remove all components (widgets, shortcuts, apps) that // belong to that package. - void removeItemsByPackageName(final ArrayList<String> packages) { + void removeItemsByPackageName(final ArrayList<String> packages, final UserHandleCompat user) { final HashSet<String> packageNames = new HashSet<String>(); packageNames.addAll(packages); @@ -4522,7 +4652,8 @@ public class Workspace extends SmoothPagedView @Override public boolean filterItem(ItemInfo parent, ItemInfo info, ComponentName cn) { - if (packageNames.contains(cn.getPackageName())) { + if (packageNames.contains(cn.getPackageName()) + && info.user.equals(user)) { cns.add(cn); return true; } @@ -4532,13 +4663,13 @@ public class Workspace extends SmoothPagedView LauncherModel.filterItemInfos(infos, filter); // Remove the affected components - removeItemsByComponentName(cns); + removeItemsByComponentName(cns, user); } // Removes items that match the application info specified, when applications are removed // as a part of an update, this is called to ensure that other widgets and application // shortcuts are not removed. - void removeItemsByApplicationInfo(final ArrayList<AppInfo> appInfos) { + void removeItemsByApplicationInfo(final ArrayList<AppInfo> appInfos, UserHandleCompat user) { // Just create a hash table of all the specific components that this will affect HashSet<ComponentName> cns = new HashSet<ComponentName>(); for (AppInfo info : appInfos) { @@ -4546,10 +4677,11 @@ public class Workspace extends SmoothPagedView } // Remove all the things - removeItemsByComponentName(cns); + removeItemsByComponentName(cns, user); } - void removeItemsByComponentName(final HashSet<ComponentName> componentNames) { + void removeItemsByComponentName(final HashSet<ComponentName> componentNames, + final UserHandleCompat user) { ArrayList<CellLayout> cellLayouts = getWorkspaceAndHotseatCellLayouts(); for (final CellLayout layoutParent: cellLayouts) { final ViewGroup layout = layoutParent.getShortcutsAndWidgets(); @@ -4568,7 +4700,7 @@ public class Workspace extends SmoothPagedView public boolean filterItem(ItemInfo parent, ItemInfo info, ComponentName cn) { if (parent instanceof FolderInfo) { - if (componentNames.contains(cn)) { + if (componentNames.contains(cn) && info.user.equals(user)) { FolderInfo folder = (FolderInfo) parent; ArrayList<ShortcutInfo> appsToRemove; if (folderAppsToRemove.containsKey(folder)) { @@ -4581,7 +4713,7 @@ public class Workspace extends SmoothPagedView return true; } } else { - if (componentNames.contains(cn)) { + if (componentNames.contains(cn) && info.user.equals(user)) { childrenToRemove.add(children.get(info)); return true; } @@ -4619,56 +4751,290 @@ public class Workspace extends SmoothPagedView stripEmptyScreens(); } - private void updateShortcut(HashMap<ComponentName, AppInfo> appsMap, ItemInfo info, - View child) { - ComponentName cn = info.getIntent().getComponent(); - if (info.getRestoredIntent() != null) { - cn = info.getRestoredIntent().getComponent(); + interface ItemOperator { + /** + * Process the next itemInfo, possibly with side-effect on {@link ItemOperator#value}. + * + * @param info info for the shortcut + * @param view view for the shortcut + * @param parent containing folder, or null + * @return true if done, false to continue the map + */ + public boolean evaluate(ItemInfo info, View view, View parent); + } + + /** + * Map the operator over the shortcuts and widgets, return the first-non-null value. + * + * @param recurse true: iterate over folder children. false: op get the folders themselves. + * @param op the operator to map over the shortcuts + */ + void mapOverItems(boolean recurse, ItemOperator op) { + ArrayList<ShortcutAndWidgetContainer> containers = getAllShortcutAndWidgetContainers(); + final int containerCount = containers.size(); + for (int containerIdx = 0; containerIdx < containerCount; containerIdx++) { + ShortcutAndWidgetContainer container = containers.get(containerIdx); + // map over all the shortcuts on the workspace + final int itemCount = container.getChildCount(); + for (int itemIdx = 0; itemIdx < itemCount; itemIdx++) { + View item = container.getChildAt(itemIdx); + ItemInfo info = (ItemInfo) item.getTag(); + if (recurse && info instanceof FolderInfo && item instanceof FolderIcon) { + FolderIcon folder = (FolderIcon) item; + ArrayList<View> folderChildren = folder.getFolder().getItemsInReadingOrder(); + // map over all the children in the folder + final int childCount = folderChildren.size(); + for (int childIdx = 0; childIdx < childCount; childIdx++) { + View child = folderChildren.get(childIdx); + info = (ItemInfo) child.getTag(); + if (op.evaluate(info, child, folder)) { + return; + } + } + } else { + if (op.evaluate(info, item, null)) { + return; + } + } + } } - if (cn != null) { - AppInfo appInfo = appsMap.get(cn); - if ((appInfo != null) && LauncherModel.isShortcutInfoUpdateable(info)) { - ShortcutInfo shortcutInfo = (ShortcutInfo) info; - BubbleTextView shortcut = (BubbleTextView) child; - shortcutInfo.restore(); - shortcutInfo.updateIcon(mIconCache); - shortcutInfo.title = appInfo.title.toString(); - shortcut.applyFromShortcutInfo(shortcutInfo, mIconCache); + } + + void updateShortcutsAndWidgets(ArrayList<AppInfo> apps) { + // Break the appinfo list per user + final HashMap<UserHandleCompat, ArrayList<AppInfo>> appsPerUser = + new HashMap<UserHandleCompat, ArrayList<AppInfo>>(); + for (AppInfo info : apps) { + ArrayList<AppInfo> filtered = appsPerUser.get(info.user); + if (filtered == null) { + filtered = new ArrayList<AppInfo>(); + appsPerUser.put(info.user, filtered); } + filtered.add(info); + } + + for (Map.Entry<UserHandleCompat, ArrayList<AppInfo>> entry : appsPerUser.entrySet()) { + updateShortcutsAndWidgetsPerUser(entry.getValue(), entry.getKey()); } } - void updateShortcuts(ArrayList<AppInfo> apps) { + private void updateShortcutsAndWidgetsPerUser(ArrayList<AppInfo> apps, + final UserHandleCompat user) { // Create a map of the apps to test against final HashMap<ComponentName, AppInfo> appsMap = new HashMap<ComponentName, AppInfo>(); + final HashSet<String> pkgNames = new HashSet<String>(); for (AppInfo ai : apps) { appsMap.put(ai.componentName, ai); + pkgNames.add(ai.componentName.getPackageName()); } + final HashSet<ComponentName> iconsToRemove = new HashSet<ComponentName>(); - ArrayList<ShortcutAndWidgetContainer> childrenLayouts = getAllShortcutAndWidgetContainers(); - for (ShortcutAndWidgetContainer layout: childrenLayouts) { - // Update all the children shortcuts - final HashMap<ItemInfo, View> children = new HashMap<ItemInfo, View>(); - for (int j = 0; j < layout.getChildCount(); j++) { - View v = layout.getChildAt(j); - ItemInfo info = (ItemInfo) v.getTag(); - if (info instanceof FolderInfo && v instanceof FolderIcon) { - FolderIcon folder = (FolderIcon) v; - ArrayList<View> folderChildren = folder.getFolder().getItemsInReadingOrder(); - for (View fv : folderChildren) { - info = (ItemInfo) fv.getTag(); - updateShortcut(appsMap, info, fv); + mapOverItems(MAP_RECURSE, new ItemOperator() { + @Override + public boolean evaluate(ItemInfo info, View v, View parent) { + if (info instanceof ShortcutInfo && v instanceof BubbleTextView) { + ShortcutInfo shortcutInfo = (ShortcutInfo) info; + ComponentName cn = shortcutInfo.getTargetComponent(); + AppInfo appInfo = appsMap.get(cn); + if (user.equals(shortcutInfo.user) && cn != null + && LauncherModel.isShortcutInfoUpdateable(info) + && pkgNames.contains(cn.getPackageName())) { + boolean promiseStateChanged = false; + boolean infoUpdated = false; + if (shortcutInfo.isPromise()) { + if (shortcutInfo.hasStatusFlag(ShortcutInfo.FLAG_AUTOINTALL_ICON)) { + // Auto install icon + PackageManager pm = getContext().getPackageManager(); + ResolveInfo matched = pm.resolveActivity( + new Intent(Intent.ACTION_MAIN) + .setComponent(cn).addCategory(Intent.CATEGORY_LAUNCHER), + PackageManager.MATCH_DEFAULT_ONLY); + if (matched == null) { + // Try to find the best match activity. + Intent intent = pm.getLaunchIntentForPackage( + cn.getPackageName()); + if (intent != null) { + cn = intent.getComponent(); + appInfo = appsMap.get(cn); + } + + if ((intent == null) || (appsMap == null)) { + // Could not find a default activity. Remove this item. + iconsToRemove.add(shortcutInfo.getTargetComponent()); + + // process next shortcut. + return false; + } + shortcutInfo.promisedIntent = intent; + } + } + + // Restore the shortcut. + shortcutInfo.intent = shortcutInfo.promisedIntent; + shortcutInfo.promisedIntent = null; + shortcutInfo.status &= ~ShortcutInfo.FLAG_RESTORED_ICON + & ~ShortcutInfo.FLAG_AUTOINTALL_ICON + & ~ShortcutInfo.FLAG_INSTALL_SESSION_ACTIVE; + + promiseStateChanged = true; + infoUpdated = true; + shortcutInfo.updateIcon(mIconCache); + LauncherModel.updateItemInDatabase(getContext(), shortcutInfo); + } + + + if (appInfo != null) { + shortcutInfo.updateIcon(mIconCache); + shortcutInfo.title = appInfo.title.toString(); + shortcutInfo.contentDescription = appInfo.contentDescription; + infoUpdated = true; + } + + if (infoUpdated) { + BubbleTextView shortcut = (BubbleTextView) v; + shortcut.applyFromShortcutInfo(shortcutInfo, + mIconCache, true, promiseStateChanged); + + if (parent != null) { + parent.invalidate(); + } + } + } + } + // process all the shortcuts + return false; + } + }); + + if (!iconsToRemove.isEmpty()) { + removeItemsByComponentName(iconsToRemove, user); + } + if (user.equals(UserHandleCompat.myUserHandle())) { + restorePendingWidgets(pkgNames); + } + } + + public void removeAbandonedPromise(String packageName, UserHandleCompat user) { + ArrayList<String> packages = new ArrayList<String>(1); + packages.add(packageName); + LauncherModel.deletePackageFromDatabase(mLauncher, packageName, user); + removeItemsByPackageName(packages, user); + } + + public void updatePackageBadge(final String packageName, final UserHandleCompat user) { + mapOverItems(MAP_RECURSE, new ItemOperator() { + @Override + public boolean evaluate(ItemInfo info, View v, View parent) { + if (info instanceof ShortcutInfo && v instanceof BubbleTextView) { + ShortcutInfo shortcutInfo = (ShortcutInfo) info; + ComponentName cn = shortcutInfo.getTargetComponent(); + if (user.equals(shortcutInfo.user) && cn != null + && shortcutInfo.isPromise() + && packageName.equals(cn.getPackageName())) { + if (shortcutInfo.hasStatusFlag(ShortcutInfo.FLAG_AUTOINTALL_ICON)) { + // For auto install apps update the icon as well as label. + mIconCache.getTitleAndIcon(shortcutInfo, + shortcutInfo.promisedIntent, user, true); + } else { + // Only update the icon for restored apps. + shortcutInfo.updateIcon(mIconCache); + } + BubbleTextView shortcut = (BubbleTextView) v; + shortcut.applyFromShortcutInfo(shortcutInfo, mIconCache, true, false); + + if (parent != null) { + parent.invalidate(); + } + } + } + // process all the shortcuts + return false; + } + }); + } + + public void updatePackageState(ArrayList<PackageInstallInfo> installInfos) { + HashSet<String> completedPackages = new HashSet<String>(); + + for (final PackageInstallInfo installInfo : installInfos) { + mapOverItems(MAP_RECURSE, new ItemOperator() { + @Override + public boolean evaluate(ItemInfo info, View v, View parent) { + if (info instanceof ShortcutInfo && v instanceof BubbleTextView) { + ShortcutInfo si = (ShortcutInfo) info; + ComponentName cn = si.getTargetComponent(); + if (si.isPromise() && (cn != null) + && installInfo.packageName.equals(cn.getPackageName())) { + si.setInstallProgress(installInfo.progress); + if (installInfo.state == PackageInstallerCompat.STATUS_FAILED) { + // Mark this info as broken. + si.status &= ~ShortcutInfo.FLAG_INSTALL_SESSION_ACTIVE; + } + ((BubbleTextView)v).applyState(false); + } + } else if (v instanceof PendingAppWidgetHostView + && info instanceof LauncherAppWidgetInfo + && ((LauncherAppWidgetInfo) info).providerName.getPackageName() + .equals(installInfo.packageName)) { + ((LauncherAppWidgetInfo) info).installProgress = installInfo.progress; + ((PendingAppWidgetHostView) v).applyState(); + } + + // process all the shortcuts + return false; + } + }); + + if (installInfo.state == PackageInstallerCompat.STATUS_INSTALLED) { + completedPackages.add(installInfo.packageName); + } + } + + // Note that package states are sent only for myUser + if (!completedPackages.isEmpty()) { + restorePendingWidgets(completedPackages); + } + } + + private void restorePendingWidgets(final Set<String> installedPackaged) { + final ArrayList<LauncherAppWidgetInfo> changedInfo = new ArrayList<LauncherAppWidgetInfo>(); + + // Iterate non recursively as widgets can't be inside a folder. + mapOverItems(MAP_NO_RECURSE, new ItemOperator() { + + @Override + public boolean evaluate(ItemInfo info, View v, View parent) { + if (info instanceof LauncherAppWidgetInfo) { + LauncherAppWidgetInfo widgetInfo = (LauncherAppWidgetInfo) info; + if (widgetInfo.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY) + && installedPackaged.contains(widgetInfo.providerName.getPackageName())) { + + changedInfo.add(widgetInfo); + + // Remove the provider not ready flag + widgetInfo.restoreStatus &= ~LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY; + LauncherModel.updateItemInDatabase(getContext(), widgetInfo); } - folder.invalidate(); - } else if (info instanceof ShortcutInfo) { - updateShortcut(appsMap, info, v); } + // process all the widget + return false; + } + }); + if (!changedInfo.isEmpty()) { + DeferredWidgetRefresh widgetRefresh = new DeferredWidgetRefresh(changedInfo, + mLauncher.getAppWidgetHost()); + if (LauncherModel.findAppWidgetProviderInfoWithComponent(getContext(), + changedInfo.get(0).providerName) != null) { + // Re-inflate the widgets which have changed status + widgetRefresh.run(); + } else { + // widgetRefresh will automatically run when the packages are updated. } } } private void moveToScreen(int page, boolean animate) { - if (!isSmall()) { + if (!workspaceInModalState()) { if (animate) { snapToPage(page); } else { @@ -4741,4 +5107,53 @@ public class Workspace extends SmoothPagedView public void getLocationInDragLayer(int[] loc) { mLauncher.getDragLayer().getLocationInDragLayer(this, loc); } + + /** + * Used as a workaround to ensure that the AppWidgetService receives the + * PACKAGE_ADDED broadcast before updating widgets. + */ + private class DeferredWidgetRefresh implements Runnable { + private final ArrayList<LauncherAppWidgetInfo> mInfos; + private final LauncherAppWidgetHost mHost; + private final Handler mHandler; + + private boolean mRefreshPending; + + public DeferredWidgetRefresh(ArrayList<LauncherAppWidgetInfo> infos, + LauncherAppWidgetHost host) { + mInfos = infos; + mHost = host; + mHandler = new Handler(); + mRefreshPending = true; + + mHost.addProviderChangeListener(this); + // Force refresh after 10 seconds, if we don't get the provider changed event. + // This could happen when the provider is no longer available in the app. + mHandler.postDelayed(this, 10000); + } + + @Override + public void run() { + mHost.removeProviderChangeListener(this); + mHandler.removeCallbacks(this); + + if (!mRefreshPending) { + return; + } + + mRefreshPending = false; + + for (LauncherAppWidgetInfo info : mInfos) { + if (info.hostView instanceof PendingAppWidgetHostView) { + PendingAppWidgetHostView view = (PendingAppWidgetHostView) info.hostView; + mLauncher.removeAppWidget(info); + + CellLayout cl = (CellLayout) view.getParent().getParent(); + // Remove the current widget + cl.removeView(view); + mLauncher.bindAppWidget(info); + } + } + } + } } diff --git a/src/com/android/launcher3/compat/AppWidgetManagerCompat.java b/src/com/android/launcher3/compat/AppWidgetManagerCompat.java new file mode 100644 index 000000000..6512d427e --- /dev/null +++ b/src/com/android/launcher3/compat/AppWidgetManagerCompat.java @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2014 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.compat; + +import android.app.Activity; +import android.appwidget.AppWidgetHost; +import android.appwidget.AppWidgetManager; +import android.appwidget.AppWidgetProviderInfo; +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.drawable.Drawable; +import android.os.Bundle; + +import com.android.launcher3.IconCache; +import com.android.launcher3.Utilities; + +import java.util.List; + +public abstract class AppWidgetManagerCompat { + + private static final Object sInstanceLock = new Object(); + private static AppWidgetManagerCompat sInstance; + + + public static AppWidgetManagerCompat getInstance(Context context) { + synchronized (sInstanceLock) { + if (sInstance == null) { + if (Utilities.isLmpOrAbove()) { + sInstance = new AppWidgetManagerCompatVL(context.getApplicationContext()); + } else { + sInstance = new AppWidgetManagerCompatV16(context.getApplicationContext()); + } + } + return sInstance; + } + } + + final AppWidgetManager mAppWidgetManager; + final Context mContext; + + AppWidgetManagerCompat(Context context) { + mContext = context; + mAppWidgetManager = AppWidgetManager.getInstance(context); + } + + public AppWidgetProviderInfo getAppWidgetInfo(int appWidgetId) { + return mAppWidgetManager.getAppWidgetInfo(appWidgetId); + } + + public abstract List<AppWidgetProviderInfo> getAllProviders(); + + public abstract String loadLabel(AppWidgetProviderInfo info); + + public abstract boolean bindAppWidgetIdIfAllowed( + int appWidgetId, AppWidgetProviderInfo info, Bundle options); + + public abstract UserHandleCompat getUser(AppWidgetProviderInfo info); + + public abstract void startConfigActivity(AppWidgetProviderInfo info, int widgetId, + Activity activity, AppWidgetHost host, int requestCode); + + public abstract Drawable loadPreview(AppWidgetProviderInfo info); + + public abstract Drawable loadIcon(AppWidgetProviderInfo info, IconCache cache); + + public abstract Bitmap getBadgeBitmap(AppWidgetProviderInfo info, Bitmap bitmap); + +} diff --git a/src/com/android/launcher3/compat/AppWidgetManagerCompatV16.java b/src/com/android/launcher3/compat/AppWidgetManagerCompatV16.java new file mode 100644 index 000000000..f599f4303 --- /dev/null +++ b/src/com/android/launcher3/compat/AppWidgetManagerCompatV16.java @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2014 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.compat; + +import android.app.Activity; +import android.appwidget.AppWidgetHost; +import android.appwidget.AppWidgetManager; +import android.appwidget.AppWidgetProviderInfo; +import android.content.Context; +import android.content.Intent; +import android.graphics.Bitmap; +import android.graphics.drawable.Drawable; +import android.os.Build; +import android.os.Bundle; + +import com.android.launcher3.IconCache; +import com.android.launcher3.Utilities; + +import java.util.List; + +class AppWidgetManagerCompatV16 extends AppWidgetManagerCompat { + + AppWidgetManagerCompatV16(Context context) { + super(context); + } + + @Override + public List<AppWidgetProviderInfo> getAllProviders() { + return mAppWidgetManager.getInstalledProviders(); + } + + @Override + public String loadLabel(AppWidgetProviderInfo info) { + return info.label.trim(); + } + + @Override + public boolean bindAppWidgetIdIfAllowed(int appWidgetId, AppWidgetProviderInfo info, + Bundle options) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) { + return mAppWidgetManager.bindAppWidgetIdIfAllowed(appWidgetId, info.provider); + } else { + return mAppWidgetManager.bindAppWidgetIdIfAllowed(appWidgetId, info.provider, options); + } + } + + @Override + public UserHandleCompat getUser(AppWidgetProviderInfo info) { + return UserHandleCompat.myUserHandle(); + } + + @Override + public void startConfigActivity(AppWidgetProviderInfo info, int widgetId, Activity activity, + AppWidgetHost host, int requestCode) { + Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_CONFIGURE); + intent.setComponent(info.configure); + intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, widgetId); + Utilities.startActivityForResultSafely(activity, intent, requestCode); + } + + @Override + public Drawable loadPreview(AppWidgetProviderInfo info) { + return mContext.getPackageManager().getDrawable( + info.provider.getPackageName(), info.previewImage, null); + } + + @Override + public Drawable loadIcon(AppWidgetProviderInfo info, IconCache cache) { + return cache.getFullResIcon(info.provider.getPackageName(), info.icon); + } + + @Override + public Bitmap getBadgeBitmap(AppWidgetProviderInfo info, Bitmap bitmap) { + return bitmap; + } +} diff --git a/src/com/android/launcher3/compat/AppWidgetManagerCompatVL.java b/src/com/android/launcher3/compat/AppWidgetManagerCompatVL.java new file mode 100644 index 000000000..c3853ab62 --- /dev/null +++ b/src/com/android/launcher3/compat/AppWidgetManagerCompatVL.java @@ -0,0 +1,139 @@ +/* + * Copyright (C) 2014 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.compat; + +import android.annotation.TargetApi; +import android.app.Activity; +import android.appwidget.AppWidgetHost; +import android.appwidget.AppWidgetProviderInfo; +import android.content.ActivityNotFoundException; +import android.content.Context; +import android.content.pm.PackageManager; +import android.content.res.Resources; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Rect; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +import android.os.Build; +import android.os.Bundle; +import android.os.UserHandle; +import android.os.UserManager; +import android.view.View; +import android.widget.Toast; + +import com.android.launcher3.IconCache; +import com.android.launcher3.R; + +import java.util.ArrayList; +import java.util.List; + +@TargetApi(Build.VERSION_CODES.L) +class AppWidgetManagerCompatVL extends AppWidgetManagerCompat { + + private final UserManager mUserManager; + private final PackageManager mPm; + + AppWidgetManagerCompatVL(Context context) { + super(context); + mPm = context.getPackageManager(); + mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE); + } + + @Override + public List<AppWidgetProviderInfo> getAllProviders() { + ArrayList<AppWidgetProviderInfo> providers = new ArrayList<AppWidgetProviderInfo>(); + for (UserHandle user : mUserManager.getUserProfiles()) { + providers.addAll(mAppWidgetManager.getInstalledProvidersForProfile(user)); + } + return providers; + } + + @Override + public String loadLabel(AppWidgetProviderInfo info) { + return info.loadLabel(mPm); + } + + @Override + public boolean bindAppWidgetIdIfAllowed(int appWidgetId, AppWidgetProviderInfo info, + Bundle options) { + return mAppWidgetManager.bindAppWidgetIdIfAllowed( + appWidgetId, info.getProfile(), info.provider, options); + } + + @Override + public UserHandleCompat getUser(AppWidgetProviderInfo info) { + return UserHandleCompat.fromUser(info.getProfile()); + } + + @Override + public void startConfigActivity(AppWidgetProviderInfo info, int widgetId, Activity activity, + AppWidgetHost host, int requestCode) { + try { + host.startAppWidgetConfigureActivityForResult(activity, widgetId, 0, requestCode, null); + } catch (ActivityNotFoundException e) { + Toast.makeText(activity, R.string.activity_not_found, Toast.LENGTH_SHORT).show(); + } catch (SecurityException e) { + Toast.makeText(activity, R.string.activity_not_found, Toast.LENGTH_SHORT).show(); + } + } + + @Override + public Drawable loadPreview(AppWidgetProviderInfo info) { + return info.loadPreviewImage(mContext, 0); + } + + @Override + public Drawable loadIcon(AppWidgetProviderInfo info, IconCache cache) { + return info.loadIcon(mContext, cache.getFullResIconDpi()); + } + + @Override + public Bitmap getBadgeBitmap(AppWidgetProviderInfo info, Bitmap bitmap) { + if (info.getProfile().equals(android.os.Process.myUserHandle())) { + return bitmap; + } + + // Add a user badge in the bottom right of the image. + final Resources res = mContext.getResources(); + final int badgeSize = res.getDimensionPixelSize(R.dimen.profile_badge_size); + final int badgeMargin = res.getDimensionPixelSize(R.dimen.profile_badge_margin); + final Rect badgeLocation = new Rect(0, 0, badgeSize, badgeSize); + + final int top = bitmap.getHeight() - badgeSize - badgeMargin; + if (res.getConfiguration().getLayoutDirection() == View.LAYOUT_DIRECTION_RTL) { + badgeLocation.offset(badgeMargin, top); + } else { + badgeLocation.offset(bitmap.getWidth() - badgeSize - badgeMargin, top); + } + + Drawable drawable = mPm.getUserBadgedDrawableForDensity( + new BitmapDrawable(res, bitmap), info.getProfile(), badgeLocation, 0); + + if (drawable instanceof BitmapDrawable) { + return ((BitmapDrawable) drawable).getBitmap(); + } + + bitmap.eraseColor(Color.TRANSPARENT); + Canvas c = new Canvas(bitmap); + drawable.setBounds(0, 0, bitmap.getWidth(), bitmap.getHeight()); + drawable.draw(c); + c.setBitmap(null); + return bitmap; + } +} diff --git a/src/com/android/launcher3/compat/LauncherActivityInfoCompat.java b/src/com/android/launcher3/compat/LauncherActivityInfoCompat.java new file mode 100644 index 000000000..90a4d1a1f --- /dev/null +++ b/src/com/android/launcher3/compat/LauncherActivityInfoCompat.java @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2014 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.compat; + +import android.content.ComponentName; +import android.content.pm.ApplicationInfo; +import android.graphics.drawable.Drawable; + +public abstract class LauncherActivityInfoCompat { + + LauncherActivityInfoCompat() { + } + + public abstract ComponentName getComponentName(); + public abstract UserHandleCompat getUser(); + public abstract CharSequence getLabel(); + public abstract Drawable getIcon(int density); + public abstract ApplicationInfo getApplicationInfo(); + public abstract long getFirstInstallTime(); + public abstract Drawable getBadgedIcon(int density); +} diff --git a/src/com/android/launcher3/compat/LauncherActivityInfoCompatV16.java b/src/com/android/launcher3/compat/LauncherActivityInfoCompatV16.java new file mode 100644 index 000000000..1d41a6ff6 --- /dev/null +++ b/src/com/android/launcher3/compat/LauncherActivityInfoCompatV16.java @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2014 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.compat; + +import android.content.ComponentName; +import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager.NameNotFoundException; +import android.content.pm.ActivityInfo; +import android.content.pm.PackageManager; +import android.content.pm.PackageInfo; +import android.content.pm.ResolveInfo; +import android.content.res.Resources; +import android.graphics.drawable.Drawable; + + +public class LauncherActivityInfoCompatV16 extends LauncherActivityInfoCompat { + private ActivityInfo mActivityInfo; + private ComponentName mComponentName; + private PackageManager mPm; + + LauncherActivityInfoCompatV16(Context context, ResolveInfo info) { + super(); + this.mActivityInfo = info.activityInfo; + mComponentName = new ComponentName(mActivityInfo.packageName, mActivityInfo.name); + mPm = context.getPackageManager(); + } + + public ComponentName getComponentName() { + return mComponentName; + } + + public UserHandleCompat getUser() { + return UserHandleCompat.myUserHandle(); + } + + public CharSequence getLabel() { + return mActivityInfo.loadLabel(mPm); + } + + public Drawable getIcon(int density) { + Drawable d = null; + if (mActivityInfo.getIconResource() != 0) { + Resources resources; + try { + resources = mPm.getResourcesForApplication(mActivityInfo.packageName); + } catch (PackageManager.NameNotFoundException e) { + resources = null; + } + if (resources != null) { + try { + d = resources.getDrawableForDensity(mActivityInfo.getIconResource(), density); + } catch (Resources.NotFoundException e) { + // Return default icon below. + } + } + } + if (d == null) { + Resources resources = Resources.getSystem(); + d = resources.getDrawableForDensity(android.R.mipmap.sym_def_app_icon, density); + } + return d; + } + + public ApplicationInfo getApplicationInfo() { + return mActivityInfo.applicationInfo; + } + + public long getFirstInstallTime() { + try { + PackageInfo info = mPm.getPackageInfo(mActivityInfo.packageName, 0); + return info != null ? info.firstInstallTime : 0; + } catch (NameNotFoundException e) { + return 0; + } + } + + public String getName() { + return mActivityInfo.name; + } + + public Drawable getBadgedIcon(int density) { + return getIcon(density); + } +} diff --git a/src/com/android/launcher3/compat/LauncherActivityInfoCompatVL.java b/src/com/android/launcher3/compat/LauncherActivityInfoCompatVL.java new file mode 100644 index 000000000..b52cf1de2 --- /dev/null +++ b/src/com/android/launcher3/compat/LauncherActivityInfoCompatVL.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2014 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.compat; + +import android.content.ComponentName; +import android.content.pm.ApplicationInfo; +import android.content.pm.LauncherActivityInfo; +import android.graphics.drawable.Drawable; +import android.os.UserHandle; + +public class LauncherActivityInfoCompatVL extends LauncherActivityInfoCompat { + private LauncherActivityInfo mLauncherActivityInfo; + + LauncherActivityInfoCompatVL(LauncherActivityInfo launcherActivityInfo) { + super(); + mLauncherActivityInfo = launcherActivityInfo; + } + + public ComponentName getComponentName() { + return mLauncherActivityInfo.getComponentName(); + } + + public UserHandleCompat getUser() { + return UserHandleCompat.fromUser(mLauncherActivityInfo.getUser()); + } + + public CharSequence getLabel() { + return mLauncherActivityInfo.getLabel(); + } + + public Drawable getIcon(int density) { + return mLauncherActivityInfo.getIcon(density); + } + + public ApplicationInfo getApplicationInfo() { + return mLauncherActivityInfo.getApplicationInfo(); + } + + public long getFirstInstallTime() { + return mLauncherActivityInfo.getFirstInstallTime(); + } + + public Drawable getBadgedIcon(int density) { + return mLauncherActivityInfo.getBadgedIcon(density); + } +} diff --git a/src/com/android/launcher3/compat/LauncherAppsCompat.java b/src/com/android/launcher3/compat/LauncherAppsCompat.java new file mode 100644 index 000000000..6efcc00fd --- /dev/null +++ b/src/com/android/launcher3/compat/LauncherAppsCompat.java @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2014 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.compat; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.graphics.Rect; +import android.os.Build; +import android.os.Bundle; + +import com.android.launcher3.Utilities; + +import java.util.List; + +public abstract class LauncherAppsCompat { + + public static final String ACTION_MANAGED_PROFILE_ADDED = + "android.intent.action.MANAGED_PROFILE_ADDED"; + public static final String ACTION_MANAGED_PROFILE_REMOVED = + "android.intent.action.MANAGED_PROFILE_REMOVED"; + + public interface OnAppsChangedCallbackCompat { + void onPackageRemoved(String packageName, UserHandleCompat user); + void onPackageAdded(String packageName, UserHandleCompat user); + void onPackageChanged(String packageName, UserHandleCompat user); + void onPackagesAvailable(String[] packageNames, UserHandleCompat user, boolean replacing); + void onPackagesUnavailable(String[] packageNames, UserHandleCompat user, boolean replacing); + } + + protected LauncherAppsCompat() { + } + + private static LauncherAppsCompat sInstance; + private static Object sInstanceLock = new Object(); + + public static LauncherAppsCompat getInstance(Context context) { + synchronized (sInstanceLock) { + if (sInstance == null) { + if (Utilities.isLmpOrAbove()) { + sInstance = new LauncherAppsCompatVL(context.getApplicationContext()); + } else { + sInstance = new LauncherAppsCompatV16(context.getApplicationContext()); + } + } + return sInstance; + } + } + + public abstract List<LauncherActivityInfoCompat> getActivityList(String packageName, + UserHandleCompat user); + public abstract LauncherActivityInfoCompat resolveActivity(Intent intent, + UserHandleCompat user); + public abstract void startActivityForProfile(ComponentName component, UserHandleCompat user, + Rect sourceBounds, Bundle opts); + public abstract void showAppDetailsForProfile(ComponentName component, UserHandleCompat user); + public abstract void addOnAppsChangedCallback(OnAppsChangedCallbackCompat listener); + public abstract void removeOnAppsChangedCallback(OnAppsChangedCallbackCompat listener); + public abstract boolean isPackageEnabledForProfile(String packageName, UserHandleCompat user); + public abstract boolean isActivityEnabledForProfile(ComponentName component, + UserHandleCompat user); +}
\ No newline at end of file diff --git a/src/com/android/launcher3/compat/LauncherAppsCompatV16.java b/src/com/android/launcher3/compat/LauncherAppsCompatV16.java new file mode 100644 index 000000000..7e5e6bf2c --- /dev/null +++ b/src/com/android/launcher3/compat/LauncherAppsCompatV16.java @@ -0,0 +1,210 @@ +/* + * Copyright (C) 2014 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.compat; + +import android.content.BroadcastReceiver; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.ActivityInfo; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; +import android.content.pm.ResolveInfo; +import android.graphics.Rect; +import android.net.Uri; +import android.os.Build; +import android.os.Bundle; +import android.provider.Settings; + +import java.util.ArrayList; +import java.util.List; + +/** + * Version of {@link LauncherAppsCompat} for devices with API level 16. + * Devices Pre-L don't support multiple profiles in one launcher so + * user parameters are ignored and all methods operate on the current user. + */ +public class LauncherAppsCompatV16 extends LauncherAppsCompat { + + private PackageManager mPm; + private Context mContext; + private List<OnAppsChangedCallbackCompat> mCallbacks + = new ArrayList<OnAppsChangedCallbackCompat>(); + private PackageMonitor mPackageMonitor; + + LauncherAppsCompatV16(Context context) { + mPm = context.getPackageManager(); + mContext = context; + mPackageMonitor = new PackageMonitor(); + } + + public List<LauncherActivityInfoCompat> getActivityList(String packageName, + UserHandleCompat user) { + final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null); + mainIntent.addCategory(Intent.CATEGORY_LAUNCHER); + mainIntent.setPackage(packageName); + List<ResolveInfo> infos = mPm.queryIntentActivities(mainIntent, 0); + List<LauncherActivityInfoCompat> list = + new ArrayList<LauncherActivityInfoCompat>(infos.size()); + for (ResolveInfo info : infos) { + list.add(new LauncherActivityInfoCompatV16(mContext, info)); + } + return list; + } + + public LauncherActivityInfoCompat resolveActivity(Intent intent, UserHandleCompat user) { + ResolveInfo info = mPm.resolveActivity(intent, 0); + if (info != null) { + return new LauncherActivityInfoCompatV16(mContext, info); + } + return null; + } + + public void startActivityForProfile(ComponentName component, UserHandleCompat user, + Rect sourceBounds, Bundle opts) { + Intent launchIntent = new Intent(Intent.ACTION_MAIN); + launchIntent.addCategory(Intent.CATEGORY_LAUNCHER); + launchIntent.setComponent(component); + launchIntent.setSourceBounds(sourceBounds); + launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + mContext.startActivity(launchIntent, opts); + } + + public void showAppDetailsForProfile(ComponentName component, UserHandleCompat user) { + String packageName = component.getPackageName(); + Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, + Uri.fromParts("package", packageName, null)); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK | + Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); + mContext.startActivity(intent, null); + } + + public synchronized void addOnAppsChangedCallback(OnAppsChangedCallbackCompat callback) { + if (callback != null && !mCallbacks.contains(callback)) { + mCallbacks.add(callback); + if (mCallbacks.size() == 1) { + registerForPackageIntents(); + } + } + } + + public synchronized void removeOnAppsChangedCallback(OnAppsChangedCallbackCompat callback) { + mCallbacks.remove(callback); + if (mCallbacks.size() == 0) { + unregisterForPackageIntents(); + } + } + + public boolean isPackageEnabledForProfile(String packageName, UserHandleCompat user) { + try { + PackageInfo info = mPm.getPackageInfo(packageName, 0); + return info != null && info.applicationInfo.enabled; + } catch (NameNotFoundException e) { + return false; + } + } + + public boolean isActivityEnabledForProfile(ComponentName component, UserHandleCompat user) { + try { + ActivityInfo info = mPm.getActivityInfo(component, 0); + return info != null && info.isEnabled(); + } catch (NameNotFoundException e) { + return false; + } + } + + private void unregisterForPackageIntents() { + mContext.unregisterReceiver(mPackageMonitor); + } + + private void registerForPackageIntents() { + IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED); + filter.addAction(Intent.ACTION_PACKAGE_REMOVED); + filter.addAction(Intent.ACTION_PACKAGE_CHANGED); + filter.addDataScheme("package"); + mContext.registerReceiver(mPackageMonitor, filter); + filter = new IntentFilter(); + filter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE); + filter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE); + mContext.registerReceiver(mPackageMonitor, filter); + } + + private synchronized List<OnAppsChangedCallbackCompat> getCallbacks() { + return new ArrayList<OnAppsChangedCallbackCompat>(mCallbacks); + } + + private class PackageMonitor extends BroadcastReceiver { + public void onReceive(Context context, Intent intent) { + final String action = intent.getAction(); + final UserHandleCompat user = UserHandleCompat.myUserHandle(); + + if (Intent.ACTION_PACKAGE_CHANGED.equals(action) + || Intent.ACTION_PACKAGE_REMOVED.equals(action) + || Intent.ACTION_PACKAGE_ADDED.equals(action)) { + final String packageName = intent.getData().getSchemeSpecificPart(); + final boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false); + + if (packageName == null || packageName.length() == 0) { + // they sent us a bad intent + return; + } + if (Intent.ACTION_PACKAGE_CHANGED.equals(action)) { + for (OnAppsChangedCallbackCompat callback : getCallbacks()) { + callback.onPackageChanged(packageName, user); + } + } else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) { + if (!replacing) { + for (OnAppsChangedCallbackCompat callback : getCallbacks()) { + callback.onPackageRemoved(packageName, user); + } + } + // else, we are replacing the package, so a PACKAGE_ADDED will be sent + // later, we will update the package at this time + } else if (Intent.ACTION_PACKAGE_ADDED.equals(action)) { + if (!replacing) { + for (OnAppsChangedCallbackCompat callback : getCallbacks()) { + callback.onPackageAdded(packageName, user); + } + } else { + for (OnAppsChangedCallbackCompat callback : getCallbacks()) { + callback.onPackageChanged(packageName, user); + } + } + } + } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)) { + // EXTRA_REPLACING is available Kitkat onwards. For lower devices, it is broadcasted + // when moving a package or mounting/un-mounting external storage. Assume that + // it is a replacing operation. + final boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, + Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT); + String[] packages = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); + for (OnAppsChangedCallbackCompat callback : getCallbacks()) { + callback.onPackagesAvailable(packages, user, replacing); + } + } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) { + final boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, + Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT); + String[] packages = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); + for (OnAppsChangedCallbackCompat callback : getCallbacks()) { + callback.onPackagesUnavailable(packages, user, replacing); + } + } + } + } +} diff --git a/src/com/android/launcher3/compat/LauncherAppsCompatVL.java b/src/com/android/launcher3/compat/LauncherAppsCompatVL.java new file mode 100644 index 000000000..e0d28b566 --- /dev/null +++ b/src/com/android/launcher3/compat/LauncherAppsCompatVL.java @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2014 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.compat; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.pm.LauncherActivityInfo; +import android.content.pm.LauncherApps; +import android.graphics.Rect; +import android.os.Build; +import android.os.Bundle; +import android.os.UserHandle; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class LauncherAppsCompatVL extends LauncherAppsCompat { + + private LauncherApps mLauncherApps; + + private Map<OnAppsChangedCallbackCompat, WrappedCallback> mCallbacks + = new HashMap<OnAppsChangedCallbackCompat, WrappedCallback>(); + + LauncherAppsCompatVL(Context context) { + super(); + mLauncherApps = (LauncherApps) context.getSystemService("launcherapps"); + } + + public List<LauncherActivityInfoCompat> getActivityList(String packageName, + UserHandleCompat user) { + List<LauncherActivityInfo> list = mLauncherApps.getActivityList(packageName, + user.getUser()); + if (list.size() == 0) { + return Collections.EMPTY_LIST; + } + ArrayList<LauncherActivityInfoCompat> compatList = + new ArrayList<LauncherActivityInfoCompat>(list.size()); + for (LauncherActivityInfo info : list) { + compatList.add(new LauncherActivityInfoCompatVL(info)); + } + return compatList; + } + + public LauncherActivityInfoCompat resolveActivity(Intent intent, UserHandleCompat user) { + LauncherActivityInfo activity = mLauncherApps.resolveActivity(intent, user.getUser()); + if (activity != null) { + return new LauncherActivityInfoCompatVL(activity); + } else { + return null; + } + } + + public void startActivityForProfile(ComponentName component, UserHandleCompat user, + Rect sourceBounds, Bundle opts) { + mLauncherApps.startMainActivity(component, user.getUser(), sourceBounds, opts); + } + + public void showAppDetailsForProfile(ComponentName component, UserHandleCompat user) { + mLauncherApps.startAppDetailsActivity(component, user.getUser(), null, null); + } + + public void addOnAppsChangedCallback(LauncherAppsCompat.OnAppsChangedCallbackCompat callback) { + WrappedCallback wrappedCallback = new WrappedCallback(callback); + synchronized (mCallbacks) { + mCallbacks.put(callback, wrappedCallback); + } + mLauncherApps.registerCallback(wrappedCallback); + } + + public void removeOnAppsChangedCallback( + LauncherAppsCompat.OnAppsChangedCallbackCompat callback) { + WrappedCallback wrappedCallback = null; + synchronized (mCallbacks) { + wrappedCallback = mCallbacks.remove(callback); + } + if (wrappedCallback != null) { + mLauncherApps.unregisterCallback(wrappedCallback); + } + } + + public boolean isPackageEnabledForProfile(String packageName, UserHandleCompat user) { + return mLauncherApps.isPackageEnabled(packageName, user.getUser()); + } + + public boolean isActivityEnabledForProfile(ComponentName component, UserHandleCompat user) { + return mLauncherApps.isActivityEnabled(component, user.getUser()); + } + + private static class WrappedCallback extends LauncherApps.Callback { + private LauncherAppsCompat.OnAppsChangedCallbackCompat mCallback; + + public WrappedCallback(LauncherAppsCompat.OnAppsChangedCallbackCompat callback) { + mCallback = callback; + } + + public void onPackageRemoved(String packageName, UserHandle user) { + mCallback.onPackageRemoved(packageName, UserHandleCompat.fromUser(user)); + } + + public void onPackageAdded(String packageName, UserHandle user) { + mCallback.onPackageAdded(packageName, UserHandleCompat.fromUser(user)); + } + + public void onPackageChanged(String packageName, UserHandle user) { + mCallback.onPackageChanged(packageName, UserHandleCompat.fromUser(user)); + } + + public void onPackagesAvailable(String[] packageNames, UserHandle user, boolean replacing) { + mCallback.onPackagesAvailable(packageNames, UserHandleCompat.fromUser(user), replacing); + } + + public void onPackagesUnavailable(String[] packageNames, UserHandle user, + boolean replacing) { + mCallback.onPackagesUnavailable(packageNames, UserHandleCompat.fromUser(user), + replacing); + } + } +} + diff --git a/src/com/android/launcher3/compat/PackageInstallerCompat.java b/src/com/android/launcher3/compat/PackageInstallerCompat.java new file mode 100644 index 000000000..0eb8754e8 --- /dev/null +++ b/src/com/android/launcher3/compat/PackageInstallerCompat.java @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2014 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.compat; + +import android.content.Context; + +import com.android.launcher3.Utilities; + +import java.util.HashSet; + +public abstract class PackageInstallerCompat { + + public static final int STATUS_INSTALLED = 0; + public static final int STATUS_INSTALLING = 1; + public static final int STATUS_FAILED = 2; + + private static final Object sInstanceLock = new Object(); + private static PackageInstallerCompat sInstance; + + public static PackageInstallerCompat getInstance(Context context) { + synchronized (sInstanceLock) { + if (sInstance == null) { + if (Utilities.isLmpOrAbove()) { + sInstance = new PackageInstallerCompatVL(context); + } else { + sInstance = new PackageInstallerCompatV16(context) { }; + } + } + return sInstance; + } + } + + public abstract HashSet<String> updateAndGetActiveSessionCache(); + + public abstract void onPause(); + + public abstract void onResume(); + + public abstract void onFinishBind(); + + public abstract void onStop(); + + public abstract void recordPackageUpdate(String packageName, int state, int progress); + + public static final class PackageInstallInfo { + public final String packageName; + + public int state; + public int progress; + + public PackageInstallInfo(String packageName) { + this.packageName = packageName; + } + + public PackageInstallInfo(String packageName, int state, int progress) { + this.packageName = packageName; + this.state = state; + this.progress = progress; + } + } +} diff --git a/src/com/android/launcher3/compat/PackageInstallerCompatV16.java b/src/com/android/launcher3/compat/PackageInstallerCompatV16.java new file mode 100644 index 000000000..1910d22ae --- /dev/null +++ b/src/com/android/launcher3/compat/PackageInstallerCompatV16.java @@ -0,0 +1,175 @@ +/* + * Copyright (C) 2014 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.compat; + +import android.content.Context; +import android.content.SharedPreferences; +import android.text.TextUtils; +import android.util.Log; + +import com.android.launcher3.LauncherAppState; + +import org.json.JSONException; +import org.json.JSONObject; +import org.json.JSONStringer; +import org.json.JSONTokener; + +import java.util.ArrayList; +import java.util.HashSet; + +public class PackageInstallerCompatV16 extends PackageInstallerCompat { + + private static final String TAG = "PackageInstallerCompatV16"; + private static final boolean DEBUG = false; + + private static final String KEY_PROGRESS = "progress"; + private static final String KEY_STATE = "state"; + + private static final String PREFS = + "com.android.launcher3.compat.PackageInstallerCompatV16.queue"; + + protected final SharedPreferences mPrefs; + + boolean mUseQueue; + boolean mFinishedBind; + boolean mReplayPending; + + PackageInstallerCompatV16(Context context) { + mPrefs = context.getSharedPreferences(PREFS, Context.MODE_PRIVATE); + } + + @Override + public void onPause() { + mUseQueue = true; + if (DEBUG) Log.d(TAG, "updates paused"); + } + + @Override + public void onResume() { + mUseQueue = false; + if (mFinishedBind) { + replayUpdates(); + } + } + + @Override + public void onFinishBind() { + mFinishedBind = true; + if (!mUseQueue) { + replayUpdates(); + } + } + + @Override + public void onStop() { } + + private void replayUpdates() { + if (DEBUG) Log.d(TAG, "updates resumed"); + LauncherAppState app = LauncherAppState.getInstanceNoCreate(); + if (app == null) { + mReplayPending = true; // try again later + if (DEBUG) Log.d(TAG, "app is null, delaying send"); + return; + } + mReplayPending = false; + ArrayList<PackageInstallInfo> updates = new ArrayList<PackageInstallInfo>(); + for (String packageName: mPrefs.getAll().keySet()) { + final String json = mPrefs.getString(packageName, null); + if (!TextUtils.isEmpty(json)) { + updates.add(infoFromJson(packageName, json)); + } + } + if (!updates.isEmpty()) { + sendUpdate(app, updates); + } + } + + /** + * This should be called by the implementations to register a package update. + */ + @Override + public synchronized void recordPackageUpdate(String packageName, int state, int progress) { + SharedPreferences.Editor editor = mPrefs.edit(); + PackageInstallInfo installInfo = new PackageInstallInfo(packageName); + installInfo.progress = progress; + installInfo.state = state; + if (state == STATUS_INSTALLED) { + // no longer necessary to track this package + editor.remove(packageName); + if (DEBUG) Log.d(TAG, "no longer tracking " + packageName); + } else { + editor.putString(packageName, infoToJson(installInfo)); + if (DEBUG) + Log.d(TAG, "saved state: " + infoToJson(installInfo) + + " for package: " + packageName); + + } + editor.commit(); + + if (!mUseQueue) { + if (mReplayPending) { + replayUpdates(); + } else if (state != STATUS_INSTALLED) { + LauncherAppState app = LauncherAppState.getInstanceNoCreate(); + ArrayList<PackageInstallInfo> update = new ArrayList<PackageInstallInfo>(); + update.add(installInfo); + sendUpdate(app, update); + } + } + } + + private void sendUpdate(LauncherAppState app, ArrayList<PackageInstallInfo> updates) { + if (app == null) { + mReplayPending = true; // try again later + if (DEBUG) Log.d(TAG, "app is null, delaying send"); + } else { + app.setPackageState(updates); + } + } + + private static PackageInstallInfo infoFromJson(String packageName, String json) { + PackageInstallInfo info = new PackageInstallInfo(packageName); + try { + JSONObject object = (JSONObject) new JSONTokener(json).nextValue(); + info.state = object.getInt(KEY_STATE); + info.progress = object.getInt(KEY_PROGRESS); + } catch (JSONException e) { + Log.e(TAG, "failed to deserialize app state update", e); + } + return info; + } + + private static String infoToJson(PackageInstallInfo info) { + String value = null; + try { + JSONStringer json = new JSONStringer() + .object() + .key(KEY_STATE).value(info.state) + .key(KEY_PROGRESS).value(info.progress) + .endObject(); + value = json.toString(); + } catch (JSONException e) { + Log.e(TAG, "failed to serialize app state update", e); + } + return value; + } + + @Override + public HashSet<String> updateAndGetActiveSessionCache() { + return new HashSet<String>(); + } +} diff --git a/src/com/android/launcher3/compat/PackageInstallerCompatVL.java b/src/com/android/launcher3/compat/PackageInstallerCompatVL.java new file mode 100644 index 000000000..16ad3792a --- /dev/null +++ b/src/com/android/launcher3/compat/PackageInstallerCompatVL.java @@ -0,0 +1,201 @@ +/* + * Copyright (C) 2014 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.compat; + +import android.content.Context; +import android.content.pm.PackageInstaller; +import android.content.pm.PackageInstaller.SessionCallback; +import android.content.pm.PackageInstaller.SessionInfo; +import android.util.Log; +import android.util.SparseArray; + +import com.android.launcher3.IconCache; +import com.android.launcher3.LauncherAppState; + +import java.util.ArrayList; +import java.util.HashSet; + +public class PackageInstallerCompatVL extends PackageInstallerCompat { + + private static final String TAG = "PackageInstallerCompatVL"; + private static final boolean DEBUG = false; + + private final SparseArray<SessionInfo> mPendingReplays = new SparseArray<SessionInfo>(); + private final HashSet<String> mPendingBadgeUpdates = new HashSet<String>(); + private final PackageInstaller mInstaller; + private final IconCache mCache; + + private boolean mResumed; + private boolean mBound; + + PackageInstallerCompatVL(Context context) { + mInstaller = context.getPackageManager().getPackageInstaller(); + LauncherAppState.setApplicationContext(context.getApplicationContext()); + mCache = LauncherAppState.getInstance().getIconCache(); + + mResumed = false; + mBound = false; + + mInstaller.registerSessionCallback(mCallback); + + // On start, send updates for all active sessions + for (SessionInfo info : mInstaller.getAllSessions()) { + mPendingReplays.append(info.getSessionId(), info); + } + } + + @Override + public HashSet<String> updateAndGetActiveSessionCache() { + HashSet<String> activePackages = new HashSet<String>(); + UserHandleCompat user = UserHandleCompat.myUserHandle(); + for (SessionInfo info : mInstaller.getAllSessions()) { + addSessionInfoToCahce(info, user); + if (info.getAppPackageName() != null) { + activePackages.add(info.getAppPackageName()); + } + } + return activePackages; + } + + private void addSessionInfoToCahce(SessionInfo info, UserHandleCompat user) { + String packageName = info.getAppPackageName(); + if (packageName != null) { + mCache.cachePackageInstallInfo(packageName, user, info.getAppIcon(), + info.getAppLabel()); + } + } + + @Override + public void onStop() { + } + + @Override + public void onFinishBind() { + mBound = true; + replayUpdates(null); + } + + @Override + public void onPause() { + mResumed = false; + } + + @Override + public void onResume() { + mResumed = true; + replayUpdates(null); + } + + @Override + public void recordPackageUpdate(String packageName, int state, int progress) { + // No op + } + + private void replayUpdates(PackageInstallInfo newInfo) { + if (DEBUG) Log.d(TAG, "updates resumed"); + if (!mResumed || !mBound) { + // Not yet ready + return; + } + if ((mPendingReplays.size() == 0) && (newInfo == null) && mPendingBadgeUpdates.isEmpty()) { + // Nothing to update + return; + } + + LauncherAppState app = LauncherAppState.getInstanceNoCreate(); + if (app == null) { + // Try again later + if (DEBUG) Log.d(TAG, "app is null, delaying send"); + return; + } + + ArrayList<PackageInstallInfo> updates = new ArrayList<PackageInstallInfo>(); + if ((newInfo != null) && (newInfo.state != STATUS_INSTALLED)) { + updates.add(newInfo); + } + for (int i = mPendingReplays.size() - 1; i >= 0; i--) { + SessionInfo session = mPendingReplays.valueAt(i); + if (session.getAppPackageName() != null) { + updates.add(new PackageInstallInfo(session.getAppPackageName(), + STATUS_INSTALLING, + (int) (session.getProgress() * 100))); + } + } + mPendingReplays.clear(); + if (!updates.isEmpty()) { + app.setPackageState(updates); + } + + if (!mPendingBadgeUpdates.isEmpty()) { + for (String pkg : mPendingBadgeUpdates) { + app.updatePackageBadge(pkg); + } + mPendingBadgeUpdates.clear(); + } + } + + private final SessionCallback mCallback = new SessionCallback() { + + @Override + public void onCreated(int sessionId) { + pushSessionBadgeToLauncher(sessionId); + } + + @Override + public void onFinished(int sessionId, boolean success) { + mPendingReplays.remove(sessionId); + SessionInfo session = mInstaller.getSessionInfo(sessionId); + if ((session != null) && (session.getAppPackageName() != null)) { + mPendingBadgeUpdates.remove(session.getAppPackageName()); + // Replay all updates with a one time update for this installed package. No + // need to store this record for future updates, as the app list will get + // refreshed on resume. + replayUpdates(new PackageInstallInfo(session.getAppPackageName(), + success ? STATUS_INSTALLED : STATUS_FAILED, 0)); + } + } + + @Override + public void onProgressChanged(int sessionId, float progress) { + SessionInfo session = mInstaller.getSessionInfo(sessionId); + if (session != null) { + mPendingReplays.put(sessionId, session); + replayUpdates(null); + } + } + + @Override + public void onActiveChanged(int sessionId, boolean active) { } + + @Override + public void onBadgingChanged(int sessionId) { + pushSessionBadgeToLauncher(sessionId); + } + + private void pushSessionBadgeToLauncher(int sessionId) { + SessionInfo session = mInstaller.getSessionInfo(sessionId); + if (session != null) { + addSessionInfoToCahce(session, UserHandleCompat.myUserHandle()); + if (session.getAppPackageName() != null) { + mPendingBadgeUpdates.add(session.getAppPackageName()); + } + mPendingReplays.put(sessionId, session); + replayUpdates(null); + } + } + }; +} diff --git a/src/com/android/launcher3/compat/UserHandleCompat.java b/src/com/android/launcher3/compat/UserHandleCompat.java new file mode 100644 index 000000000..2ae673171 --- /dev/null +++ b/src/com/android/launcher3/compat/UserHandleCompat.java @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2014 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.compat; + +import android.content.Intent; +import android.os.Build; +import android.os.UserHandle; + +import com.android.launcher3.Utilities; + +public class UserHandleCompat { + private UserHandle mUser; + + private UserHandleCompat(UserHandle user) { + mUser = user; + } + + private UserHandleCompat() { + } + + public static UserHandleCompat myUserHandle() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { + return new UserHandleCompat(android.os.Process.myUserHandle()); + } else { + return new UserHandleCompat(); + } + } + + static UserHandleCompat fromUser(UserHandle user) { + if (user == null) { + return null; + } else { + return new UserHandleCompat(user); + } + } + + UserHandle getUser() { + return mUser; + } + + @Override + public String toString() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { + return mUser.toString(); + } else { + return ""; + } + } + + @Override + public boolean equals(Object other) { + if (!(other instanceof UserHandleCompat)) { + return false; + } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { + return mUser.equals(((UserHandleCompat) other).mUser); + } else { + return true; + } + } + + @Override + public int hashCode() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { + return mUser.hashCode(); + } else { + return 0; + } + } + + /** + * Adds {@link UserHandle} to the intent in for L or above. + * Pre-L the launcher doesn't support showing apps for multiple + * profiles so this is a no-op. + */ + public void addToIntent(Intent intent, String name) { + if (Utilities.isLmpOrAbove() && mUser != null) { + intent.putExtra(name, mUser); + } + } +} diff --git a/src/com/android/launcher3/compat/UserManagerCompat.java b/src/com/android/launcher3/compat/UserManagerCompat.java new file mode 100644 index 000000000..1374b4e49 --- /dev/null +++ b/src/com/android/launcher3/compat/UserManagerCompat.java @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2014 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.compat; + +import android.content.Context; +import android.graphics.drawable.Drawable; +import android.os.Build; + +import com.android.launcher3.Utilities; + +import java.util.List; + +public abstract class UserManagerCompat { + protected UserManagerCompat() { + } + + public static UserManagerCompat getInstance(Context context) { + if (Utilities.isLmpOrAbove()) { + return new UserManagerCompatVL(context); + } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { + return new UserManagerCompatV17(context); + } else { + return new UserManagerCompatV16(); + } + } + + public abstract List<UserHandleCompat> getUserProfiles(); + public abstract long getSerialNumberForUser(UserHandleCompat user); + public abstract UserHandleCompat getUserForSerialNumber(long serialNumber); + public abstract Drawable getBadgedDrawableForUser(Drawable unbadged, UserHandleCompat user); + public abstract CharSequence getBadgedLabelForUser(CharSequence label, UserHandleCompat user); +} diff --git a/src/com/android/launcher3/compat/UserManagerCompatV16.java b/src/com/android/launcher3/compat/UserManagerCompatV16.java new file mode 100644 index 000000000..32f972e85 --- /dev/null +++ b/src/com/android/launcher3/compat/UserManagerCompatV16.java @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2014 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.compat; + +import android.graphics.drawable.Drawable; + +import java.util.ArrayList; +import java.util.List; + +public class UserManagerCompatV16 extends UserManagerCompat { + + UserManagerCompatV16() { + } + + public List<UserHandleCompat> getUserProfiles() { + List<UserHandleCompat> profiles = new ArrayList<UserHandleCompat>(1); + profiles.add(UserHandleCompat.myUserHandle()); + return profiles; + } + + public UserHandleCompat getUserForSerialNumber(long serialNumber) { + return UserHandleCompat.myUserHandle(); + } + + public Drawable getBadgedDrawableForUser(Drawable unbadged, + UserHandleCompat user) { + return unbadged; + } + + public long getSerialNumberForUser(UserHandleCompat user) { + return 0; + } + + public CharSequence getBadgedLabelForUser(CharSequence label, UserHandleCompat user) { + return label; + } +} diff --git a/src/com/android/launcher3/compat/UserManagerCompatV17.java b/src/com/android/launcher3/compat/UserManagerCompatV17.java new file mode 100644 index 000000000..055359afe --- /dev/null +++ b/src/com/android/launcher3/compat/UserManagerCompatV17.java @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2014 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.compat; + +import android.content.Context; +import android.graphics.drawable.Drawable; +import android.os.UserHandle; +import android.os.UserManager; + +import java.util.ArrayList; +import java.util.List; + +public class UserManagerCompatV17 extends UserManagerCompatV16 { + protected UserManager mUserManager; + + UserManagerCompatV17(Context context) { + mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE); + } + + public long getSerialNumberForUser(UserHandleCompat user) { + return mUserManager.getSerialNumberForUser(user.getUser()); + } + + public UserHandleCompat getUserForSerialNumber(long serialNumber) { + return UserHandleCompat.fromUser(mUserManager.getUserForSerialNumber(serialNumber)); + } +} + diff --git a/src/com/android/launcher3/compat/UserManagerCompatVL.java b/src/com/android/launcher3/compat/UserManagerCompatVL.java new file mode 100644 index 000000000..19eeabdcf --- /dev/null +++ b/src/com/android/launcher3/compat/UserManagerCompatVL.java @@ -0,0 +1,65 @@ + +/* + * Copyright (C) 2014 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.compat; + +import android.content.Context; +import android.content.pm.PackageManager; +import android.graphics.drawable.Drawable; +import android.os.UserHandle; +import android.os.UserManager; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class UserManagerCompatVL extends UserManagerCompatV17 { + private final PackageManager mPm; + + UserManagerCompatVL(Context context) { + super(context); + mPm = context.getPackageManager(); + } + + @Override + public List<UserHandleCompat> getUserProfiles() { + List<UserHandle> users = mUserManager.getUserProfiles(); + if (users == null) { + return Collections.EMPTY_LIST; + } + ArrayList<UserHandleCompat> compatUsers = new ArrayList<UserHandleCompat>( + users.size()); + for (UserHandle user : users) { + compatUsers.add(UserHandleCompat.fromUser(user)); + } + return compatUsers; + } + + @Override + public Drawable getBadgedDrawableForUser(Drawable unbadged, UserHandleCompat user) { + return mPm.getUserBadgedIcon(unbadged, user.getUser()); + } + + @Override + public CharSequence getBadgedLabelForUser(CharSequence label, UserHandleCompat user) { + if (user == null) { + return label; + } + return mPm.getUserBadgedLabel(label, user.getUser()); + } +} + |