Android 13 about launcher3 (1)

Android 13 Launcher3
android13#launcher3#分屏相关

Launcher3修改 wm density界面布局不改变
/packages/apps/Launcher3/src/com/android/launcher3/InvariantDeviceProfile.java
Launcher的默认配置加载类,通过InvariantDeviceProfile方法可以看出,
CellLayout显示的应用行数和列数可以通过findClosestDeviceProfiles查询XML配置来读取配参

Launcher3图标布局原理解析

Android 13 diff

index 02ebb15cd1..36ce9bf7bf 100644
--- a/packages/apps/Launcher3/src/com/android/launcher3/util/DisplayController.java
+++ b/packages/apps/Launcher3/src/com/android/launcher3/util/DisplayController.java
@@ -284,7 +284,7 @@ public class DisplayController implements ComponentCallbacks, SafeCloseable {
         if (change != 0) {
             mInfo = newInfo;
             final int flags = change;
-            MAIN_EXECUTOR.execute(() -> notifyChange(displayInfoContext, flags));
+            //MAIN_EXECUTOR.execute(() -> notifyChange(displayInfoContext, flags));
         }
     }

Android 11 diff

./packages/apps/Launcher3/src/com/android/launcher3/util/ConfigMonitor.java

   @Override
    public void onDisplayChanged(int displayId) {
        if (displayId != mDisplayId) {
            return;
        }
        Display display = getDefaultDisplay(mContext);
        display.getRealSize(mTmpPoint1);
 
        if (!mRealSize.equals(mTmpPoint1) && !mRealSize.equals(mTmpPoint1.y, mTmpPoint1.x)) {
            LogUtils.d(TAG, String.format("Display size changed from %s to %s", mRealSize, mTmpPoint1));
            notifyChange();
            return;
        }
 
        display.getCurrentSizeRange(mTmpPoint1, mTmpPoint2);
        if (!mSmallestSize.equals(mTmpPoint1) || !mLargestSize.equals(mTmpPoint2)) {
            LogUtils.d(TAG, String.format("Available size changed from [%s, %s] to [%s, %s]",
                    mSmallestSize, mLargestSize, mTmpPoint1, mTmpPoint2));
            notifyChange();
        }
    }
 
    public synchronized void notifyChange() {
 
        if (mCallback != null) {
            Consumer<Context> callback = mCallback;
            mCallback = null;
            new MainThreadExecutor().execute(() -> {
 
        //add text
        //LauncherAppMonitor.getInstance(mContext).onUIConfigChanged();
        //callback.accept(mContext);
        //add text
 
            });
        }
    }
Android 13 关于旋转屏幕之后,按home键回Launcher3失效
//自动旋转
public static final String ACCELEROMETER_ROTATION = "accelerometer_rotation";
adb shell settings get system accelerometer_rotation  --> 0 off 1 on

Android 12之后,Launcher3有两个模式,一个是平板,另一个是手机.

手机模式:桌面默认是不可以旋转的.

桌面设置页面:桌面空白处长按,进入home settings,有个allow home screen rotation就是旋转开关,手机模式默认是关闭的,平板模式这个偏好隐藏了.

./packages/apps/Launcher3/res/values/config.xml    
<string name="settings_fragment_name" translatable="false">com.android.launcher3.settings.SettingsActivity$LauncherSettingsFragment</string>

./packages/apps/Launcher3/src/com/android/launcher3/settings/SettingsActivity.java
public static class LauncherSettingsFragment extends PreferenceFragmentCompat 
{
    protected boolean initPreference(Preference preference) {
            switch (preference.getKey()) {
                case NOTIFICATION_DOTS_PREFERENCE_KEY:
                    return !WidgetsModel.GO_DISABLE_NOTIFICATION_DOTS;

                case ALLOW_ROTATION_PREFERENCE_KEY:
                    DisplayController.Info info =
                            DisplayController.INSTANCE.get(getContext()).getInfo();
                    if (info.isTablet(info.realBounds)) {
                        // Launcher supports rotation by default. No need to show this setting.
                        //是平板,不显示这个选项
                        return false;
                    }
                    // Initialize the UI once //非平板,默认显示,
                    preference.setDefaultValue(RotationHelper.getAllowRotationDefaultValue(info));//控制是否旋转
                    return true;
                    ...
                    
    }
}

./packages/apps/Launcher3/src/com/android/launcher3/states/RotationHelper.java
    public static boolean getAllowRotationDefaultValue(DisplayController.Info info) {
        android.util.Log.d("tag","info.currentSize.x: " +info.currentSize.x);
        android.util.Log.d("tag","info.currentSize.y: " +info.currentSize.y);
        float originalSmallestWidth = dpiFromPx(Math.min(info.currentSize.x, info.currentSize.y),
                DENSITY_DEVICE_STABLE);
        return originalSmallestWidth >= MIN_TABLET_WIDTH;//MIN_TABLET_WIDTH = 600;
    }
    
    
    public static float dpiFromPx(float size, int densityDpi) {
        float densityRatio = (float) densityDpi / DisplayMetrics.DENSITY_DEFAULT;//DENSITY_DEFAULT=160;
        return (size / densityRatio);
    }
    
    //关于DENSITY_DEVICE_STABLE
    private static int getDeviceDensity() {
        //ro.sf.lcd_density的值在初始化进程的时候从build.prop里读取写入一次,之后不会修改
        //qemu.sf.lcd_density覆写上边的值,目的是在模拟器的时候可以动态修改
        return SystemProperties.getInt("qemu.sf.lcd_density",
                SystemProperties.getInt("ro.sf.lcd_density", DENSITY_DEFAULT));
    }
    
    initialize()->初始化setIgnoreAutoRotateSettings
    
    private void setIgnoreAutoRotateSettings(boolean ignoreAutoRotateSettings,
            DisplayController.Info info) {
        // On large devices we do not handle auto-rotate differently.
        mIgnoreAutoRotateSettings = ignoreAutoRotateSettings;
        if (!mIgnoreAutoRotateSettings) {
            mHomeRotationEnabled = LauncherPrefs.get(mActivity).get(ALLOW_ROTATION);
            LauncherPrefs.get(mActivity).addListener(this, ALLOW_ROTATION);
        } else {
            LauncherPrefs.get(mActivity).removeListener(this, ALLOW_ROTATION);
        }
    }
    

    //手动控制屏幕旋转的方式
    
    private void setOritation(int i) {
        try {
            IWindowManager windowManagerService = WindowManagerGlobal.getWindowManagerService();
 		if (i == 0) {
                windowManagerService.freezeRotation(0);
                Settings.System.putInt(this.mContext.getContentResolver(), "accelerometer_rotation", 0);//关闭自动旋转
            } else if (i == 90) {
                windowManagerService.freezeRotation(1);
                Settings.System.putInt(this.mContext.getContentResolver(), "accelerometer_rotation", 0);
            } else if (i == 180) {
                windowManagerService.freezeRotation(2);
                Settings.System.putInt(this.mContext.getContentResolver(), "accelerometer_rotation", 0);
            } else if (i == 270) {
                windowManagerService.freezeRotation(3);
                Settings.System.putInt(this.mContext.getContentResolver(), "accelerometer_rotation", 0);
            } else if (i == -1) {
                Settings.System.putInt(this.mContext.getContentResolver(), "accelerometer_rotation", 1);//打开自动旋转
            }
        } catch (Exception e) {
		...
       }
    }
    
    Settings.System.getInt(mContext.getContentResolver(), Settings.System.USER_ROTATION, 0);
    adb shell settings get system user_rotation(修改后查询)
    
    
//修改  默认打开主界面旋转
+++ b/packages/apps/Launcher3/res/xml/launcher_preferences.xml
@@ -45,7 +45,7 @@
         android:key="pref_allowRotation"
         android:title="@string/allow_rotation_title"
         android:summary="@string/allow_rotation_desc"
-        android:defaultValue="false"
+        android:defaultValue="true"
         android:persistent="true"
         launcher:logIdOn="615"
         launcher:logIdOff="616" />
diff --git a/packages/apps/Launcher3/src/com/android/launcher3/states/RotationHelper.java b/packages/apps/Launcher3/src/com/android/launcher3/states/RotationHelper.java
index 7b4e2485ce..6693f9f123 100644
--- a/packages/apps/Launcher3/src/com/android/launcher3/states/RotationHelper.java
+++ b/packages/apps/Launcher3/src/com/android/launcher3/states/RotationHelper.java
@@ -55,7 +55,7 @@ public class RotationHelper implements OnSharedPreferenceChangeListener,
         // original dimensions to determine if rotation is allowed of not.
         float originalSmallestWidth = dpiFromPx(Math.min(info.currentSize.x, info.currentSize.y),
                 DENSITY_DEVICE_STABLE);
-        return originalSmallestWidth >= MIN_TABLET_WIDTH;
+        return true;//originalSmallestWidth >= MIN_TABLET_WIDTH;//add text
     }
从源头隐藏某个apk不在最近应用(RecentView)显示
//这个改法:再需要隐藏的app,按Recent,有动画时显得卡顿,建议可以在Launcher3内尝试隐藏
frameworks/base/services/core/java/com/android/server/wm/RecentTasks.java

    /**
     * @return the list of recent tasks for presentation.
     */
    private ArrayList<ActivityManager.RecentTaskInfo> getRecentTasksImpl(int maxNum, int flags,
            boolean getTasksAllowed, int userId, int callingUid) {
        final boolean withExcluded = (flags & RECENT_WITH_EXCLUDED) != 0;

        if (!isUserRunning(userId, FLAG_AND_UNLOCKED)) {
            Slog.i(TAG, "user " + userId + " is still locked. Cannot load recents");
            return new ArrayList<>();
        }
        loadUserRecentsLocked(userId);

        final Set<Integer> includedUsers = getProfileIds(userId);
        includedUsers.add(Integer.valueOf(userId));

        final ArrayList<ActivityManager.RecentTaskInfo> res = new ArrayList<>();
        final int size = mTasks.size();
        int numVisibleTasks = 0;
        for (int i = 0; i < size; i++) {
            final Task task = mTasks.get(i);

            if (isVisibleRecentTask(task)) {
                numVisibleTasks++;
                if (isInVisibleRange(task, i, numVisibleTasks, withExcluded)) {
                    // Fall through
                } else {
                    // Not in visible range
                    continue;
                }
            } else {
                // Not visible
                continue;
            }

            // Skip remaining tasks once we reach the requested size
            if (res.size() >= maxNum) {
                continue;
            }

            // Only add calling user or related users recent tasks
            if (!includedUsers.contains(Integer.valueOf(task.mUserId))) {
                if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Skipping, not user: " + task);
                continue;
            }

            ...

            //add text
            ComponentName cn = task.intent.getComponent();
            if(cn != null && cn.getPackageName().equals("com.xxx.xxx")){
                continue;
            }else{
                res.add(createRecentTaskInfo(task, true /* stripExtras */));
            }
            //add text
            
        }
        return res;
    }

Android T Launcher3
Android T Launcher3_recentView

T replace default launcher

关于3.0Ver 利用role不需要删除旧Launcher栈的补充.

case 1: 单独使用role,确实不需要删除旧Launcher栈,唯一需要注意点的是要在Launcher启动之前,把android.app.role.HOME替换,

所以需要在framework里某个必经之路上做文章...

//about home role
packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/role/model/HomeRoleBehavior.java
packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/role/ui/ManageRoleHolderStateLiveData.java

packages/modules/Permission/service/java/com/android/role/RoleService.java
addRoleHolderAsUser(...)
removeRoleHolderAsUser(...)
getRoleHoldersAsUser(...)


frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java

+import android.app.role.RoleManager;
+import java.util.concurrent.Executor;
+import java.util.function.Consumer;
+

    @Override
    public void systemReady() {
        // In normal flow, systemReady is called before other system services are ready.
        // So it is better not to bind keyguard here.
        mKeyguardDelegate.onSystemReady();
        ...
        mAutofillManagerInternal = LocalServices.getService(AutofillManagerInternal.class);
        mGestureLauncherService = LocalServices.getService(GestureLauncherService.class);
+        setDefaultLauncherItemToHomeRole(mContext);//add
    }
    
    public void setDefaultLauncherItemToHomeRole(Context context) {
        RoleManager roleManager = context.getSystemService(RoleManager.class);
        String packageName = SystemProperties.get("persist.xx.def_xxx_launcher", null);
        
        List<String> list = roleManager_1.getRoleHolders("android.app.role.HOME");
        boolean repeat_flag = false;
        for (int i = 0; i < list.size(); i++) {
            if (list.get(i).equals(packageName)) {
                flag = true;
            }
        }
        
        if (repeat_flag) return;
        
        if (packageName != null && !"".equals(packageName)) {
            String roleName = "android.app.role.HOME";
            boolean add = true;
            int flags = 0;
            UserHandle user = Process.myUserHandle();
            Log.d("tag", "role: " + roleName + ", package: " + packageName);
            Executor executor = context.getMainExecutor();
            Consumer<Boolean> callback = successful -> {
                if (successful) {
                    Log.d("tag", "Success , role: " + roleName + ", package: " + packageName);
                } else {
                    Log.d("tag", "Failed , role: " + roleName + ", package: " + packageName);
                }
            };
            roleManager.addRoleHolderAsUser(roleName, packageName, flags, user, executor, callback);
        }
    }

case 2:ResolverActivity

frameworks/base/core/java/com/android/internal/app/ResolverActivity.java
onCreate()->rebuildList()->onPostListReady()->isAutolaunching()...                        

    protected void onCreate(Bundle savedInstanceState, Intent intent,
            CharSequence title, int defaultTitleRes, Intent[] initialIntents,
            List<ResolveInfo> rList, boolean supportsAlwaysUseOption) {
        setTheme(appliedThemeResId());
        super.onCreate(savedInstanceState);
        //add text
        if(true){
            setDefaultLauncher("com.xx.xxx");
            finish();
            return;
        }
        //add text
        mQuietModeManager = createQuietModeManager();
        ...
    }    
    
    //add text
    private List<ResolveInfo> getResolveInfoList() {
        PackageManager pm = getPackageManager();
        Intent intent = new Intent(Intent.ACTION_MAIN, null);
        intent.addCategory(Intent.CATEGORY_HOME);
        intent.addCategory(Intent.CATEGORY_DEFAULT);
        return pm.queryIntentActivities(intent, 0);
    }

    private ResolveInfo getCurrentLauncher() {
        PackageManager pm = getPackageManager();
        Intent intent = new Intent(Intent.ACTION_MAIN, null);
        intent.addCategory(Intent.CATEGORY_HOME);
        intent.addCategory(Intent.CATEGORY_DEFAULT);
        return pm.resolveActivity(intent, 0);
    }

    private void setDefaultLauncher(String packageName) {
        PackageManager pm = getPackageManager();
        ResolveInfo oldCurrentLauncher = getCurrentLauncher();
        List<ResolveInfo> packageInfos = getResolveInfoList();

        ResolveInfo customerLauncher = null;

        for (ResolveInfo ri : packageInfos) {
            if (!TextUtils.isEmpty(ri.activityInfo.packageName) && !TextUtils.isEmpty(packageName)
                    && TextUtils.equals(ri.activityInfo.packageName, packageName)) {
                customerLauncher = ri;
            }
        }

        if (customerLauncher == null) return;

        pm.clearPackagePreferredActivities(oldCurrentLauncher.activityInfo.packageName);//clear old Launcher
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(Intent.ACTION_MAIN);
        intentFilter.addCategory(Intent.CATEGORY_HOME);
        intentFilter.addCategory(Intent.CATEGORY_DEFAULT);
        ComponentName componentName = new ComponentName(customerLauncher.activityInfo.packageName,
                customerLauncher.activityInfo.name);
        ComponentName[] componentNames = new ComponentName[packageInfos.size()];
        int defaultMatch = 0;
        for (int i = 0; i < packageInfos.size(); i++) {
            ResolveInfo resolveInfo = packageInfos.get(i);
            componentNames[i] = new ComponentName(resolveInfo.activityInfo.packageName, resolveInfo.activityInfo.name);
            if (defaultMatch < resolveInfo.match) {
                defaultMatch = resolveInfo.match;
            }
        }
        pm.clearPackagePreferredActivities(oldCurrentLauncher.activityInfo.packageName);
        pm.addPreferredActivity(intentFilter, defaultMatch, componentNames, componentName);
    }
    //add text

Android13设置默认Launcher分析
Android13设置默认Launcher分析
RK3588 Android13 预安装自己的apk应用及把这个应用设置为默认桌面
Android R设置默认桌面

相关推荐
忘忧记6 小时前
Python MySQL SQLServer操作
android
万岳科技系统开发6 小时前
外卖系统开发实战:从架构设计到代码实现
android·小程序·开源
standxy7 小时前
通过轻易云平台实现聚水潭数据高效集成到MySQL的技术方案
android·数据库·mysql
he_wen_jian9 小时前
Android 项目引入gradle Connect timed out
android
哎呦没10 小时前
企业OA管理系统:Spring Boot技术实现与案例研究
android·spring boot·后端
李新_11 小时前
一文聊聊Flutter多业务混合工程实践
android·flutter
weixin_SAG14 小时前
7天掌握SQL - 第三天:MySQL实践与索引优化
android·sql·mysql
疯狂的皮卡16 小时前
【安卓脚本】Android工程中文硬编码抽取
android
菜鸟、小高17 小时前
从0开始学PHP面向对象内容之常用设计模式(适配器,桥接,装饰器)
android·设计模式·php
找藉口是失败者的习惯18 小时前
Jetpack Compose 生命周期介绍
android·ui