多用户的概念在早于4.2的源码中,就已经可以初见端倪.
直到4.2,才真真正正地将之扶正.
功能详解见:
http://www.evolife.cn/html/2012/67701.html
喜欢刷版本号的谷歌在今年已经把Android从4.0刷到了4.2,而大部分机器连果冻豆都还没吃上,单核的二儿子已经跪在了4.2门前。好在4.1到4.2只是改动不大的小幅升级,名称还是果冻豆,新加的特色功能包括通知栏控件,锁屏小插件和平板中的多账户。今天我们就来给大家介绍一下Android 4.2的重点功能——能让一家人共享一个Android设备的多用户功能。
多账户的概念跟Windows电脑上的账户类似,绝对不是什么噱头,不过Android系统的多账户还是有一些独特的地方。
首先,第一个使用平板的用户默认为平板管理员,可以在平板设置选项的用户区添加或删除帐号。网络设置和安装应用程序的权限在平板所有用户中通用和共享,但墙纸、主屏幕、锁屏布局、PIN码、屏幕明亮度、单个应用设置等则各不相同。新用户注册后大约会占用十几MB空间(Nexus 7初始账户大小在12.78MB左右),不过随着下载应用数量的增加,占用的空间也会越来越大。
跟Windows操作系统的不同之处在于,4.2系统的其他用户帐户中正在运行的后台程序也会占用一定的RAM空间。而最明显的区别是用户之间的应用程序无法共享,这样一来想要用没付费的帐户在同一台机器下载其他账户已经付费的内容时,需要在商店用已付费的帐户密码重新登录,如果想要保护隐私的话就没办法跟其他用户共享付费软件,希望谷歌在后续版本中能解决这个问题。(好在多个账户重复下载同一应用时不会真的在存储空间里出现相同的两个应用,而是进行虚拟下载和安装,不用担心占用空间。)
此外,用户之间不能直接共享数据,即使将平板和电脑相连,也只能浏览当前用户的文件,切换帐号需要重新装载,虽说有些麻烦但是安全性得到了充分保证。
除了多账户,4.2新增的通知栏控件也非常实用,一直以来靠第三方ROM实现的这项功能终于在原生系统上出现。另外锁屏界面也变得更丰富,滑屏到左边可以预览相机程序(此时再往上滑才能解锁,不用担心误触),右边显示可选的小插件界面(不能添加第三方插件),显然自带的这些小插件是不能满足需求的,且一个锁屏界面只能放一个插件,切换必须一屏一屏滑,目测第三方ROM中,第三方插件和多插件自定义功能会很快出现。
添加桌面插件时原本的图标会自动让位
Android 4.2在细节上吸收了不少第三方厂商或者ROM的人性化功能。只是如果没有特殊需求,4.2相比4.1来说改动不大,普通用户没有必须升级的必要。当然作为特色的多账户功能出现在手机上也是迟早的事,这样一来通过账户切换,同学们再也不用担心手机藏不住小秘密。
从最初拿到手的源码, 本以为可以很兴奋地看到这个新功能, 实际上却大失所望.
直到前不久, 才有客户提出此功能的需求, 查一查还真查到多用户支持的一些补丁.
直接从上层设置入手:
packages/apps/Settings/res/xml/settings_headers.xml <!-- Manage users --> <header android:fragment="com.android.settings.users.UserSettings" android:icon="@drawable/ic_settings_multiuser" android:title="@string/user_settings_title" android:id="@+id/user_settings" /> 显示或隐藏由JAVA源码控制: packages/apps/Settings/src/com/android/settings/Settings.java private void updateHeaderList(List<Header> target) { final boolean showDev = true;/*mDevelopmentPreferences.getBoolean( DevelopmentSettings.PREF_SHOW, android.os.Build.TYPE.equals("eng"));*/ int i = 0; mHeaderIndexMap.clear(); while (i < target.size()) { Header header = target.get(i); // Ids are integers, so downcasting int id = (int) header.id; if (id == R.id.operator_settings || id == R.id.manufacturer_settings) { Utils.updateHeaderToSpecificActivityFromMetaDataOrRemove(this, target, header); } else if (id == R.id.wifi_settings) { // Remove WiFi Settings if WiFi service is not available. if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI)) { target.remove(i); } } else if (id == R.id.bluetooth_settings) { // Remove Bluetooth Settings if Bluetooth service is not available. //if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH)) { if (SystemProperties.get("ro.rk.bt_enable", "true").equals("false")) { target.remove(header); } } else if (id == R.id.hdmi_settings) { if("true".equals(SystemProperties.get("ro.zed.noHdmi"))){ target.remove(header); } }else if (id == R.id.data_usage_settings) { // Remove data usage when kernel module not enabled final INetworkManagementService netManager = INetworkManagementService.Stub .asInterface(ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE)); try { if (!netManager.isBandwidthControlEnabled()) { target.remove(i); } } catch (RemoteException e) { // ignored } } else if (id == R.id.account_settings) { int headerIndex = i + 1; i = insertAccountsHeaders(target, headerIndex); }/** 重点看下这个地方 *****/ else if (id == R.id.user_settings) { if (!UserHandle.MU_ENABLED || !UserManager.supportsMultipleUsers() || Utils.isMonkeyRunning()) { target.remove(i); } } else if (id == R.id.development_settings) { if (!showDev) { target.remove(i); } } else if(id == R.id.hdmi_settings){ if(!hasHdmiFeature()){ target.remove(header); } } if (target.get(i) == header && UserHandle.MU_ENABLED && UserHandle.myUserId() != 0 && !ArrayUtils.contains(SETTINGS_FOR_RESTRICTED, id)) { target.remove(i); } // Increment if the current one wasn't removed by the Utils code. if (target.get(i) == header) { // Hold on to the first header, when we need to reset to the top-level if (mFirstHeader == null && HeaderAdapter.getHeaderType(header) != HeaderAdapter.HEADER_TYPE_CATEGORY) { mFirstHeader = header; } mHeaderIndexMap.put(id, i); i++; } } }
分别来看看三个条件的情况:
!UserHandle.MU_ENABLED: public static final boolean MU_ENABLED = true; !UserManager.supportsMultipleUsers() /** * Returns whether the system supports multiple users. * @return true if multiple users can be created, false if it is a single user device. * @hide */ public static boolean supportsMultipleUsers() { return getMaxSupportedUsers() > 1; } /** * Returns the maximum number of users that can be created on this device. A return value * of 1 means that it is a single user device. * @hide * @return a value greater than or equal to 1 */ public static int getMaxSupportedUsers() { // Don't allow multiple users on certain builds if (android.os.Build.ID.startsWith("JVP")) return 1; return SystemProperties.getInt("fw.max_users", Resources.getSystem().getInteger(R.integer.config_multiuserMaximumUsers)); }
Utils.isMonkeyRunning()这个条件一般不成立
所以, 一般比较可控的地方就在于:
if (android.os.Build.ID.startsWith("JVP")) return 1; return SystemProperties.getInt("fw.max_users", Resources.getSystem().getInteger(R.integer.config_multiuserMaximumUsers));
可以考虑在build.prop中添加属性:
fw.max_users=x x >1
如果上面属性没有添加, 那另一部分就是修改
config_multiuserMaximumUsers的值.
frameworks/base/core/res/res/values/config.xml
<!-- Maximum number of supported users -->
<integer name="config_multiuserMaximumUsers">8</integer>
修改上面的值,请留意是否有overlay.