Launcher3 custom wallpaper cannot be restored after being stretched after rotation, launcher3 stretch
Copyright. For more information, see the source:
Http://www.cnblogs.com/sickworm/p/3966857.html
MTK8382/8121 platform.
Description: After setting a custom image as a wallpaper, the portrait screen is rotated when the screen is displayed. The image is stretched because the resolution is too small. The image is then rotated to the landscape screen without restoration.
This problem has been solved in the past two days. It has been studied for a long time and has taken many detours. Finally, it was found that the Launcher had a bug in reading SharePreferences.
The bug is generated as follows:
When the custom wallpaper is set in Launcher3 (the built-in wallpaper is not recorded. android. launcher3.WallpaperCropActivity. record the resolution of the wallpaper set in xml, and submit the resolution to WallpaperManager (via suggestWallpaperDimension ()). The specific function is: updateWallpaperDimensions () in WallpaperCropActivity. java, which is called by setWallpaper () of WallpaperCropActivity. java;
Launcher3 re-executes onCreate () after each rotation, and submits the resolution of the current wallpaper to WallpaperManager. The resolution submission function is in setWallpaperDimension () In Workspace. java. The problem is that setWallpaperDimension () cannot get the SharedPreferences modified by updateWallpaperDimensions (). As a result, it submits the default wallpaper resolution of 1920x1080, resulting in low-resolution wallpaper stretching.
To solve this problem, modify the flag of getSharedPreferences () in setWallpaperDimension () In Workspace. java and change MODE_PRIVATE to MODE_MULTI_PROCESS. After modification, access is successful.
My problem is:
According to Android Developer's explanation:
MODE_PRIVATE:
File creation mode: the default mode, where the created file can only be accessed by the calling application (or all applications sharing the same user ID).
That is, MODEL_PRIVATE can only be called by the same application or application with the same userID. In this case, the two activities can be accessed together. (Workspace. java uses the context of Launcher. java. The two Activity PIDs are different, and the uid is the same)
At the same time, I also read the explanation of MODE_MULTI_PROCESS:
MODE_MULTI_PROCESS:
SharedPreference loading flag: when set, the file on disk will be checked for modification even if the shared preferences instance is already loaded in this process. This behavior is sometimes desired in cases where the application has multiple processes, all writing to the same SharedPreferences file. Generally there are better forms of communication between processes, though.
This was the legacy (but undocumented) behavior in and before Gingerbread (Android 2.3) and this flag is implied when targetting such releases. For applications targetting SDK versions greater than Android 2.3, this flag must be explicitly set if desired.
This flag is used to allow applications with multiple processes to access the same SharedPreferences. It seems that MODEL_MULTI_PROCESS should be used again.
So I want to find the getSharedPreference implementation code and see how it handles these flags. We can't find the implementation method from the parent class level of the Activity until we find this article:
Http://blog.csdn.net/qinjuning/article/details/7310620
To know how ContextImpl implemented Context, and then found the answer:
The ContextImpl class has the getSharedPreferences implementation. It indicates that in the MODE_MULTI_PROCESS flag, getSharedPreferences performs reload. In other words, MODE_PRIVATE will not re-read SharedPreferences.
Here, I finally understood what he meant: In the previous bug, it was not because SharedPreferences failed to be obtained, but because there was no reload, so I didn't get the resolution information of the new write. Because I didn't notice this problem before, I took a detour.
However, there is another problem: every time the Launcher rotates, it will restart the Activity and call onCreate. Why is my getSharePreferences still old? Continue to observe the getSharedPreferences of android. app. ContextImpl:
@Overridepublic SharedPreferences getSharedPreferences(String name, int mode) {Log.w("Launcher", "contextImpl: " + this, new RuntimeException("getSp").fillInStackTrace());SharedPreferencesImpl sp;synchronized (ContextImpl.class) {if (sSharedPrefs == null) {Log.e("Launcher", "all init");sSharedPrefs = new ArrayMap<String, ArrayMap<String, SharedPreferencesImpl>>();}final String packageName = getPackageName();ArrayMap<String, SharedPreferencesImpl> packagePrefs = sSharedPrefs.get(packageName);if (packagePrefs == null) {Log.e("Launcher", "package init");packagePrefs = new ArrayMap<String, SharedPreferencesImpl>();sSharedPrefs.put(packageName, packagePrefs);}// At least one application in the world actually passes in a null// name. This happened to work because when we generated the file name// we would stringify it to "null.xml". Nice.if (mPackageInfo.getApplicationInfo().targetSdkVersion <Build.VERSION_CODES.KITKAT) {if (name == null) {name = "null";}}sp = packagePrefs.get(name);if (sp == null) {File prefsFile = getSharedPrefsFile(name);sp = new SharedPreferencesImpl(prefsFile, mode);packagePrefs.put(name, sp);Log.e("Launcher", "new sp");return sp;}Log.e("Launcher", "old sp");}if ((mode & Context.MODE_MULTI_PROCESS) != 0 ||getApplicationInfo().targetSdkVersion < android.os.Build.VERSION_CODES.HONEYCOMB) {// If somebody else (some other process) changed the prefs// file behind our back, we reload it. This has been the// historical (if undocumented) behavior.sp.startReloadIfChangedUnexpectedly();Log.e("Launcher", "reload");}return sp;}
Log. e ("Launcher",...); is the debugging information I added. First, the system checks whether sSharedPrefs has content and obtains the prefsFile of the corresponding package. If sSharedPrefs cannot be found, it will be re-read from the xml file. Finally, a judgment is added. If the MODE_MULTI_PROCESS variable is set or the system lower than Android 2.2 reload from the xml file by default to keep the latest SharedPreferences data.
Note that the sSharedPrefs variable is assigned only in getSharedPreferences. That is to say, the data of SharedPreferences always follows the ContextImpl instance and only obtains data from the getSharedPreferences () method. That is to say, when the screen is rotated, the data obtained by calling getSharedPreferences () is obtained from the sSharedPrefs variable. We can also see from the following Log information that there is no Log print for "new sp" to be rotated, "new sp" appears only when force stop and clear data are set for Launcher3 ".
Rotation Log prompt:
09-11 08:47:19.599: E/Launcher(4628): launcher:com.android.launcher3.Launcher@42392ac809-11 08:47:19.599: E/Launcher(4628): mBase:android.app.ContextImpl@424c189809-11 08:47:19.608: E/Launcher(4628): old sp09-11 08:47:19.727: E/Launcher(4628): old sp09-11 08:47:19.731: E/Launcher(4628): reload09-11 08:47:19.932: E/Launcher(4628): old sp
Force stop prompt:
09-11 08:48:29.456: E/Launcher(5271): launcher:com.android.launcher3.Launcher@4238f22009-11 08:48:29.456: E/Launcher(5271): mBase:android.app.ContextImpl@42391ab809-11 08:48:29.489: E/Launcher(5271): all init09-11 08:48:29.489: E/Launcher(5271): package init09-11 08:48:29.493: E/Launcher(5271): new sp09-11 08:48:29.679: E/Launcher(5271): new sp09-11 08:48:29.766: E/Launcher(5271): old sp09-11 08:48:29.767: E/Launcher(5271): old sp09-11 08:48:29.790: E/Launcher(5271): old sp
There are three connected old sp, only the second of which is the read resolution, and the other two are the SharedPreferences of LauncherAppState. At this time, the Launcher3 code has been changed to MODE_MULTI_PROCESS, so "reload" information is displayed during rotation.
That is to say, the sSharedPrefs value is always saved during rotation. However, through Log printing, we found that the contextImpl of each getSharedPreferences () is different!
Note that the context of the execution method is executed by the mBase private member of the ContextThemeWrapper parent class of the Activity. To obtain the mBase, you can print this out in getSharedPreferences, you can also perform reflection in the Activity. The reflection method is used here:
try {Log.e("Launcher", "launcher:" + this);java.lang.reflect.Field f = Activity.class.getSuperclass().getDeclaredField("mBase");f.setAccessible(true);Context s = (Context) f.get(this);Log.e("Launcher", "mBase:" + s);} catch(Exception e) {e.printStackTrace();}
ContextImpl is different, but the sSharedPrefs data is still stored, and sSharedPrefs cannot be assigned by other methods. It can only be guessed that the original context is passed in the prototype mode during rotation. For the Rotation Processing of Launcher3, I only find the broadcast ACTION_CONFIGURATION_CHANGE, But I have commented out the code in it and can still work normally. It is estimated that the code is controlled at a lower level.
The specific code has not been found, because it has to be moved. Study now!
800*480 Android 23 how does one set wallpaper? (Not stretched)
First, you need to download the professional resolution matching wallpaper. We recommend that you use wallpaper resources in pods, because they all match your mobile phone, including dynamic and static ones... This is generally okay.
However, if you want to use the wallpaper of the multi-view desktop, it will be more troublesome. All the original wallpapers on my multi-view desktop are not suitable for the screen, so you need to adjust them yourself or.
Samsung I9300 high imitation machine. I unloaded the launcher3 starter that comes with the system, but the interface remained unchanged. After I restarted the system, I started it and shut it down on the boot interface.
Whether the caller tries to delete the installed dial.