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设置默认桌面

相关推荐
火柴就是我7 小时前
Flutter 项目本地 Maven 引入 AAR 找不到?一次 Gradle 路径问题排查
android
火柴就是我8 小时前
Android 打包报错 25.0.3
android·前端
码上有光8 小时前
Linux进程通信——共享内存、消息队列和信号量
android·linux·运维·共享内存·通信
Android打工仔12 小时前
Kotlin 协程源码解析:DispatchedContinuation 里的 Dispatcher 从哪里来?
android·kotlin
打工仔折腾 AI12 小时前
从BPE到SentencePiece:Transformer分词原理与Python实战对比
android·人工智能·python·深度学习·langchain·transformer·ai agent 实战
Dovis(誓平步青云)13 小时前
几个方案来回选不定?做一个随时切换的候选推荐页
android·java·服务器·开发语言·javascript·数据库·智能化
恋猫de小郭17 小时前
KMP 又改了编译流程, Separate Compilation 禁止了 `commonMain` 的依赖穿透
android·前端·flutter
执明wa17 小时前
Android RecyclerView 实战:点击频道栏切换对应内容
android·开发语言·windows·microsoft·android studio
新鲜势力呀17 小时前
PHP 定时数据同步实战:从第三方接口超时到异步同步 + 增量更新架构优化全过程
android
星间都市山脉19 小时前
RecoveryUI 圆角屏安全边距配置及代码调用链
android·java·linux·windows·ubuntu