Android源码开发-Android系统时间时区以及12/24小时制等修改方法详解

来源:互联网 发布:有关打击电信网络诈骗 编辑:程序博客网 时间:2024/05/16 08:50

         首先声明一下:以下讲解是在Android4.2源码环境下下开发,一般的手机用户仅作参考,不保证实现。

         问题提出:我们知道,Android源码出厂默认勾选在有网络情况下“自动更新时间”与“自动更新时区”,所以不需要我们再手动修改时间,即使修改了一联网也会自动重设,但是,应客户需求,在设备没有网络的情况下,就需要手动修改系统时间。这样问题来了,怎么修改系统时间时区?

         参考Android“系统设置”源码可知,非一般应用非root用户不能修改系统时间,时区倒是可以随便修改。所以,那些想要在一般的应用中修改时间的人,只能无可奈何了。现在只剩下root权限下的系统应用才可以修改系统时间的可能性了。问题又来了,这个系统应用该怎么编写呢?有以下两种方式:

        方式一:在Android系统源码的环境下用make来编译:
    1. 在应用程序的AndroidManifest.xml中的manifest节点中加入android:sharedUserId="android.uid.system"这个属性。
    2. 修改Android.mk文件,加入LOCAL_CERTIFICATE := platform这一行
    3. 使用mm命令来编译,生成的apk就有修改系统时间的权限了。
        方式二:像一般的应用一样开发:
    1. 同上,加入android:sharedUserId="android.uid.system"这个属性。
    2. 使用eclipse编译出apk文件,但是这个apk文件是不能用的。
    3. 用压缩软件打开apk文件,删掉META-INF目录下的CERT.SF和CERT.RSA两个文件。
    4. 使用目标系统的platform密钥来重新给apk文件签名。

      对于以上两种方式,它们各有优劣。首先方式一虽然步奏简单,但在系统源码下不好调试应用,非常麻烦。方式二生成的应用不能直接安装,必须放在源码编译成功的out目录下级的system/app目录下,然后一起生成镜像文件。根据对比,我选择方式二。

      对于方式二,问题又来了。假设我成功签名了,然后成功安装了,那么我怎么调用这个app修改时间呢?当然了,我可以利用以下代码实现在一个应用中打开另外一个应用

Intent intent = getPackageManager().getLaunchIntentForPackage("com.android.aidl.service");    startActivity(intent); 
其中com.android.aidl.service是所要打开的另外一个应用包名。貌似可以实现哦~但是呢,你想想,两个进程,两个应用,大量的修改时间代码以及界面存在另外一个应用,而不是你的主应用中,是不是很难维护呢?更专业的做法是尽量多的把主要工作统一在一个主应用中完成,另外一个应用知识充当简单的接口或者服务的功能即可。所以我的做法是什么呢?我把需要修改时间的应用定义成一个“服务”,并且提供修改系统时间的“接口”,全部界面代码以及实现代码全部在我的主应用中实现,在主应用中传递时间参数给该服务即可。服务进程没有界面,这是简单实现即可。这样间接实现了“一般应用修改系统时间的愿望”。不知道读者有没有看懂,懂不懂没关系,来跟我一起探索“如何在一般应用中”用“不一般的方法”实现“修改系统时间”吧~

一、首先涉及到的知识点是:跨进程调用Service(AIDL Service),具体知识点读者请自行查找资料,这里只提供实现方法,下面是该服务应用的实现。

      以上是该服务应用的目录结构,其实代码非常简单,下面我们详细解读。

      1、SetDateTime.aidl

package com.android.aidl.service;interface SetDateTime {int setTimeToSystem(long MilliSec);    void setDateTime(int year, int month, int day, int hour, int minute) ;}
      该文件非常简单,定义了一个接口,并定义了两个函数,这两个函数将实现修改系统时间。在写好这个借口之后,工程将自动在gen目录下生产一个对应的java文件,用户必用干涉。

       2、SetDateTimeService.java

package com.android.aidl.service;import java.io.DataOutputStream;import java.io.File;import java.io.IOException;import java.util.Calendar;import android.app.Service;import android.content.Intent;import android.os.IBinder;import android.os.RemoteException;import android.os.SystemClock;import android.util.Log;public class SetDataTimeService extends Service {    private final static String TAG = "com.ideal.SetDateTimeService";    @Override    public IBinder onBind(Intent intent) {        Log.v(TAG, "OnBind-ok");        return new MyBinder();    }        private class MyBinder extends SetDateTime.Stub{        @Override        public int setTimeToSystem(long MilliSec) throws RemoteException{            if( SystemClock.setCurrentTimeMillis(MilliSec)){            Log.v(TAG, "SetTimeToSystem-ok");            return 0;            }            else{            Log.v(TAG, "SetTimeToSystem-fail");            return -1;            }        }@Overridepublic void setDateTime(int year, int month, int day, int hour,int minute) throws RemoteException {/********获得root权限********/File rootUser = new File("/system/xbin/ru");Process myProcess=null;DataOutputStream os = null;try{        if(rootUser.exists()) {  myProcess=Runtime.getRuntime().exec(rootUser.getAbsolutePath());        } else {   myProcess=Runtime.getRuntime().exec("su");         }        os = new DataOutputStream(myProcess.getOutputStream());    os.writeBytes("chmod 666 /dev/alarm" + "\n");os.writeBytes("exit $?\n");           try {myProcess.waitFor();} catch (InterruptedException e) {e.printStackTrace();}   }catch (IOException e) {      e.printStackTrace();      Log.v(TAG, "getroot-fail");  }finally {          if(os != null) {         try {os.close();} catch (IOException e) {e.printStackTrace();}        }  }/**********设置系统时间***********/  Calendar c = Calendar.getInstance();      c.set(Calendar.YEAR, year);      c.set(Calendar.MONTH, month-1);      c.set(Calendar.DAY_OF_MONTH, day);      c.set(Calendar.HOUR_OF_DAY, hour);      c.set(Calendar.MINUTE, minute);   long when = c.getTimeInMillis();  if (when / 1000 < Integer.MAX_VALUE) {      if(SystemClock.setCurrentTimeMillis(when)){      Log.v(TAG, "setDateAndTime-ok");      }else{       Log.v(TAG, "setDateAndTime-fail");      }   }  long now = Calendar.getInstance().getTimeInMillis();  if(now - when > 1000)    Log.v(TAG, "setDateAndTime-fail");}    }}
        该文件定义了一个服务,并实现了接口的两个方法。该两个方法都可以修改系统时间。该段代码是“系统时间设置”代码的简化版,原理是一致的。
        3、AndroidManifext.xml

<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android"      package="com.android.aidl.service"      android:versionCode="1"      android:versionName="1.0"      android:sharedUserId="android.uid.system">    <uses-sdk android:minSdkVersion="8" />    <application android:icon="@drawable/icon"         android:label="@string/app_name">        <service android:name="SetDataTimeService">            <intent-filter>                <action android:name="com.android.aidl.setdatetime" />             </intent-filter>        </service>    </application></manifest>
        这个文件声明了一个服务,并制定了系统参数android:sharedUserId="android.uid.system",当指定了这个系统参数之后,这个应用将不会像一般的应用一样安装了,只能在源码中的out目录下的system/app目录下运行安装。

       以上是服务应用的讲解,如果不是很理解的话请点击下载服务应用源码。

      使用eclipse编译出apk文件,但是这个apk文件是不能用的。用压缩软件打开apk文件,删掉META-INF目录下的CERT.SF和CERT.RSA两个文件,然后给apk文件签名。签名方式如下:将源码目录下的build/target/product/secure目录下的platform.pk8和platform.x509.pem两个目录拷出来,放在与签名工具sighapk.jar同一个目录,signapk.jar请点击这里下载,然后打开命令行窗口执行:

java -jar signapk.jar platform.x509.pem platform.pk8 source.apk signed.apk
其中souce.apk是已经删掉META-INF目录下的CERT.SF和CERT.RSA两个文件的应用,signed.apk是得到的签过名的应用,可以随便命名。然后将这个应用直接拷贝到out目录下级的system/app目录下即可,在制作镜像时自然后包进去。到目前为止,我们的服务应用已经跑起来了,那么我们一般的应用该怎么调用这个服务实现进程之间的通信呢?请往下看:

二、一般应用调用服务应用实现”进程通信“


      以上是一般应用的结构,从上图可以看出,要想调用调用前面系统应用目录下的应用时,必须按着正确的步奏来。首先第一个是新建一个一模一样的aidl文件,接口代码也一样,包结构也一模一样,建好之后工程会自动在gen目录生成相应的java文件。完成以上步奏就可以直接调用该服务接口实现修修改系统时间了哦。一下是代码实现:

        private String actionName = "com.android.aidl.setdatetime";private SetDateTime setDateTime=null;private ServiceConnection connection =new ServiceConnection(){@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {setDateTime = SetDateTime.Stub.asInterface(service);Log.v(TAG, "onServiceConnected-ok");if(setDateTime==null){return;}try {//setDateTime.setTimeToSystem(System.currentTimeMillis()+24*3600*1000);setDateTime.setDateTime(2013, 4, 4, 4, 4);} catch (RemoteException e) {e.printStackTrace();}}@Override    public void onServiceDisconnected(ComponentName name) {setDateTime=null;Log.v(TAG, "onServiceDisconnected-ok");}};@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_flash);Intent intent  = new Intent(actionName);bindService(intent, connection, Context.BIND_AUTO_CREATE);Log.v(TAG, "bindService-ok");}
       以上只是整个java文件的一部分代码,该部分代码包含了所有的修改系统时间的实现代码。在退出该界面之后记得解绑服务。

@Overrideprotected void onDestroy() {super.onDestroy();                this.unbindService(connection);}

三、时区的修改一般的应用都可以实现,很简单

1、首先在AndroidManifext.xml中假如权限

    <uses-permission android:name="android.permission.SET_TIME_ZONE"/>
2、设置相应的时区

AlarmManager timeZone= (AlarmManager)getSystemService(ALARM_SERVICE);timeZone.setTimeZone("Asia/Shanghai");

四、修改系统12/24小时制

        Android源码中默认使用12小时制,如果想要改成24小时制的话,方法如下:

1、到源码目录 frameworks/base/packages/SettingsProvider/res/values/defaults.xml 文件中增加一行:

<string name="time_12_24">24</string>

2、到源码目录 frameworks/base/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java文件中的loadSystemSettings()方法中增加下面一行设置时间格式:

loadStringSetting(stmt,Settings.System.TIME_12_24,R.string.time_12_24);

3、可以用以下代码查看系统是否是24小时制:

ContentResolver c = getContentResolver(); String strTimeFormat = android.provider.Settings.System.getString(c,android.provider.Settings.System.TIME_12_24); if(strTimeFormat.equals("24")){Log.e("time", "The system time is 24 hour format"); }else{Log.e("time", "The system time is 12 hour format"); }

       以上基本全部讲解完了。这种方式确实很好,间接实现了通过一般的应用来修改系统时间。用户可以完全在一般应用中编写界面与实现函数,只是最后简单调用一下服务应用即可修改时间。该方法现在已经运用到我的项目中来了,效果不错~祝你成功~如果在过程中出错或者有什么疑问,欢迎在线留言哦,我一定热心回答~

全部源码工具打包在这里





0 0