Android Framework 自定义系统选项

Android系统默认提供了一些Contont Provider,如 Contacts ProviderDocuments ProviderSettings Provider等等。这些provider源码都放在frameworks/base/core/java/android/provider文件夹中。

当我们需要自定义一些系统设置,比如在Settings界面中增加了一个设置keyguard特效的选项,当用户在Settings界面中设置了某个特效后,keyguard那边能够读取这个设置项,并做出相应的改变。很显然的这里涉及到IPC,通常我们可以自己写一个Provider,但如果你有源码就完全可以复用Android提供的已有Settings Provider,达到简洁统一。

打开frameworks/base/core/java/android/provider/Settings.java文件,导航到NameValueCache类。在这个类中你会看到很多我们熟悉的一些系统设置(WIFI、亮度等等),这些值都会储存到数据库中(系统的或者用户的)。我们在这个类中增加一个常量来标记我们新增的设置项:

public static final String KEYGUARD_TRANSITION_TYPE = "keyguard_transition_type"; 

修改完之后需要重新编译一下framework。

现在Settings Provider中有了我们需要的字段,下一步就是怎么往里存储和读取了。方法很简单,从上面Settings.java文件中可以看到有很多put和get方法,我们可以使用这些方法来对NameValueCache中声明的字段进行存取操作。

import static android.provider.Settings.System.KEYGUARD_TRANSITION_TYPE;

Settings.System.putInt(getContentResolver(),
                    KEYGUARD_TRANSITION_TYPE, value);

int currentValue = Settings.System.getInt(
                    getContentResolver(), KEYGUARD_TRANSITION_TYPE,);

Settings.System.putIntForUser(getContentResolver(),
                    KEYGUARD_TRANSITION_TYPE, value, UserHandle.USER_CURRENT);

int currentValue = Settings.System.getIntForUser(
                    getContentResolver(), KEYGUARD_TRANSITION_TYPE,
                    UserHandle.USER_CURRENT);

需要注意的是上面带有用户参数的方法(*ForUser)是Hide属性的。

最后需要一个数据监听器,这样才能做到实时更新选项:

    private static final Uri mUri = Settings.System.getUriFor(KEYGUARD_TRANSITION_TYPE);

    private final ContentObserver mObserver = new ContentObserver(new Handler()) {
        public void onChange(boolean selfChange) {
           //you can do something here
        }
    };

    getContentResolver().registerContentObserver(mUri, false, mObserver);

Android 系统监听切换用户事件

try{                                                                                                                                                                           
        ActivityManagerNative.getDefault().registerUserSwitchObserver(
            new IUserSwitchObserver.Stub() {
              @Override
              public void onUserSwitching(int newUserId, IRemoteCallback reply) {
                switchUser(newUserId, reply);//Here, you can do something you want
              }
         
              @Override
              public void onUserSwitchComplete(int newUserId) throws RemoteException {
              }
            });  
      } catch (RemoteException e) { 
        // TODO Auto-generated catch block
        e.printStackTrace();
      }
}

ref : frameworks/base/services/java/com/android/server/WallpaperManagerService.java : 519

Xcode 5.1 编译 Android 源码错误

升级Xcode后,在编译android 4.4.2是出现如下错误:

SyntaxError: Unable to find any JNI methods for org/chromium/ui/gfx/BitmapHelper.

解决方法有两个:

  • 回退xcode版本

  • 修改文件external/base/android/jni_generator/jni_generator.py :

    +import platform
    -p = subprocess.Popen(args=[‘cpp’, ‘-fpreprocessed’],
    +system = platform.system()
    +if system == ‘Darwin’:
    + cpp_args = [‘cpp’]
    +else:
    + cpp_args = [‘cpp’, ‘-fpreprocessed’]
    +p = subprocess.Popen(args=cpp_args,
    + stdin=subprocess.PIPE,
    + stdout=subprocess.PIPE,
    + stderr=subprocess.PIPE)
    

OSX 切换 JAVA 版本

OSX 10.9.4

查看当前Java版本

java -version
java version "1.7.0_51"
Java(TM) SE Runtime Environment (build 1.7.0_51-b13)
Java HotSpot(TM) 64-Bit Server VM (build 24.51-b03, mixed mode)

查看系统可用的Java版本

/usr/libexec/java_home -v "1.6*"
/System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home

导出JAVA HOME

export JAVA_HOME=`/usr/libexec/java_home -v '1.6*'`

查看更改后的JAVA版本

java -version

java version "1.6.0_65"
Java(TM) SE Runtime Environment (build 1.6.0_65-b14-466.1-11M4716)
Java HotSpot(TM) 64-Bit Server VM (build 20.65-b04-466.1, mixed mode)

AOSP 使用 GMS Location Service

AOSP现在跟GMS真是一毛钱关系都没有了。但是如果没有GMS,在AOSP上就用不了网络定位功能(当然在国内最好还是baidu、高德,既快又准)。当你在AOSP上安装了完整的GMS以后,会发现网络定位还是不能用,查看log是因为签名不正确导致Network Location service无法启动。对这个问题的解决方案如下: 打开frameworks/base/core/res/res/values/config.xml配置文件,定位到<string-array name=”config_locationProviderPackageNames” translatable=”false”>。这个文件的原始内容为:

<string-array name="config_locationProviderPackageNames" translatable="false">
          <!-- The standard AOSP fused location provider -->
          <item>com.android.location.fused</item>
</string-array>

系统只会调用在这里注册过的Location Provider,所以需要把GMS的Location Provider在这里注册一下,修改后的内容如下:

<string-array name="config_locationProviderPackageNames" translatable="false">
          <!-- GMS location provider -->                                                                                                           
          <item>com.google.android.gms</item>
          <!-- The standard AOSP fused location provider -->
          <item>com.android.location.fused</item>
</string-array>

修改完成后重新编译framework然后push到机器。 Done!

PS:经测试发现,GMS Location Provider只需要GmsCore.apk,GoogleServicesFramework.apk这两个apk即可。你可以把他们放在vender/google/gms目录下,建立一个Android.mk,内容如下:

LOCAL_PATH:= $(call my-dir) 

include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE := GmsCore.apk
LOCAL_MODULE_CLASS := APPS
LOCAL_PRIVILEGED_MODULE := true
LOCAL_CERTIFICATE := PRESIGNED
LOCAL_MODULE_PATH := $(TARGET_OUT)/priv-app
LOCAL_SRC_FILES := GmsCore.apk
include $(BUILD_PREBUILT)
 
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE := GoogleServicesFramework.apk
LOCAL_MODULE_CLASS := APPS
LOCAL_PRIVILEGED_MODULE := true
LOCAL_CERTIFICATE := PRESIGNED
LOCAL_MODULE_PATH := $(TARGET_OUT)/priv-app
LOCAL_SRC_FILES := GoogleServicesFramework.apk
include $(BUILD_PREBUILT)              

这样以后编译image的时候就会自动预装了。