定製替換Android桌面(home screen)

定製替換Android桌面(home screen)
發表於99 天前 ⁄ 編程開發 ⁄ 評論數 1

替換Android桌面的相關問題:

1、想將home screen換成自己寫的activity,該如何實現?

在你要設置爲home screen的那個activity的androidManifest.xml中的<intent-filter>標籤中加上這幾句 話<category android:name="android.intent.category.HOME" />
<category android:name="android.intent.category.DEFAULT" />運行後,重啓模擬器會彈出一個選擇進入哪個界面的對話框

2、怎樣將系統默認的home screen刪除?

重新編譯launcher源碼,去掉配置文件中的home屬性和HOME屬性。。
在自己的activity中加入這兩個屬性,然後重新燒系統。

 

以下是定製Android的完整思路和步驟:

如果你要定製一個Android系統,你想用你自己的Launcher(Home)作主界面來替換Android自己的Home,而且不希望用戶安裝的Launcher來替換掉你的Launcher.
我們可以通過修改Framework來實現這樣的功能。

這裏以Android2.1的源代碼爲例來實際說明。

1)首先了解一下Android的啓動過程。
Android系統的啓動先從Zygote開始啓動,然後……(中間的過程就不說了)…..一直到了SystemServer(framework)這個地方,看到這段代碼:

  1. /**
  2. * This method is called from Zygote to initialize the system. This will cause the native
  3. * services (SurfaceFlinger, AudioFlinger, etc..) to be started. After that it will call back
  4. * up into init2() to start the Android services.
  5. */
  6. native public static void init1(String[] args);
  7. public static void main(String[] args) {
  8. if (SamplingProfilerIntegration.isEnabled()) {
  9. SamplingProfilerIntegration.start();
  10. timer = new Timer();
  11. timer.schedule(new TimerTask() {
  12. @Override
  13. public void run() {
  14. SamplingProfilerIntegration.writeSnapshot(“system_server”);
  15. }
  16. }, SNAPSHOT_INTERVAL, SNAPSHOT_INTERVAL);
  17. }
  18. // The system server has to run all of the time, so it needs to be
  19. // as efficient as possible with its memory usage.
  20. VMRuntime.getRuntime().setTargetHeapUtilization(0.8f);
  21. System.loadLibrary(“android_servers”);
  22. init1(args);
  23. }
  24. public static final void init2() {
  25. Log.i(TAG, “Entered the Android system server!”);
  26. Thread thr = new ServerThread();
  27. thr.setName(“android.server.ServerThread”);
  28. thr.start();
  29. }
  30. }

從SystemServer的main函數開始啓動各種服務。
首先啓動init1,然後啓動init2.
從上面的註釋可以看到:init1這個方法時被Zygote調用來初始化系統的,init1會啓動native的服務如SurfaceFlinger,AudioFlinger等等,這些工作做完以後會回調init2來啓動Android的service。

這裏我們主要來關注init2的過程。
init2中啓動ServerThread線程,
ServerThread中啓動了一系列的服務,比如這些:

  1. ActivityManagerService
  2. EntropyService
  3. PowerManagerService
  4. TelephonyRegistry
  5. PackageManagerService
  6. AccountManagerService
  7. BatteryService
  8. HardwareService
  9. Watchdog
  10. SensorService
  11. BluetoothService
  12. StatusBarService
  13. ClipboardService
  14. InputMethodManagerService
  15. NetStatService
  16. ConnectivityService
  17. AccessibilityManagerService
  18. NotificationManagerService
  19. MountService
  20. DeviceStorageMonitorService
  21. LocationManagerService
  22. SearchManagerService
  23. FallbackCheckinService
  24. WallpaperManagerService
  25. AudioService
  26. BackupManagerService
  27. AppWidgetService

這些大大小小的服務起來以後,開始
((ActivityManagerService)ActivityManagerNative.getDefault()).systemReady()
在systemReady後開始開始啓動Launcher。

在尋找Launcher的時候是根據HOME的filter(在Manifest中定義的<category android:name=”android.intent.category.HOME” />)來過濾。
然後根據filter出來的HOME來啓動,如果只有一個HOME,則啓動這個HOME,如果用戶自己裝了HOME,那就會彈出來一個列表供用戶選擇。

我們現在希望從這裏彈出我們自己定製的Launcher,同時也不希望彈出選擇HOME的界面,我們不希望用戶修改我們的home,比如我們的home上放了好多廣告,以及強制安裝的程序,不希望用戶把它幹掉。

我們可以通過這樣來實現:

2) 定義一個私有的filter選項,然後用這個選項來過濾HOME.
一般情況下我們使用Manifest中定義的<category android:name=”android.intent.category.HOME”來過濾的,我們現在增加一個私有的HOME_FIRST過濾。

在Intent.java(frameworks/base/core/java/android/content/Intent.java)中添加兩行代碼

  1. //添加CATEGORY_HOME_FIRST
  2. @SdkConstant(SdkConstantType.INTENT_CATEGORY)
  3. public static final String CATEGORY_HOME_FIRST = “android.intent.category.HOME_FIRST”;

3)修改和CATEGORY_HOME相關的所有的地方,都改成HOME_FIRST,主要是framework中的這幾個地方:

  1. frameworks/base/services/java/com/android/server/am/ActivityManagerService.java中
  2. //intent.addCategory(Intent.CATEGORY_HOME);
  3. 改成intent.addCategory(Intent.CATEGORY_HOME_FIRST);
  4. //if (r.intent.hasCategory(Intent.CATEGORY_HOME)) {
  5. 改成if (r.intent.hasCategory(Intent.CATEGORY_HOME_FIRST)) { //Intent.CATEGORY_HOME -> Intent.CATEGORY_HOME_FIRST
  6. frameworks/base/services/java/com/android/server/am/HistoryRecorder.java中
  7. // _intent.hasCategory(Intent.CATEGORY_HOME) &&
  8. 改成 _intent.hasCategory(Intent.CATEGORY_HOME_FIRST) && //Intent.CATEGORY_HOME->Intent.CATEGORY_HOME_FIRST
  9. frameworks/policies/base/mid/com/android/internal/policy/impl/MidWindowManager.java中
  10. //mHomeIntent.addCategory(Intent.CATEGORY_HOME);
  11. 改成 mHomeIntent.addCategory(Intent.CATEGORY_HOME_FIRST);
  12. frameworks/policies/base/mid/com/android/internal/policy/impl/RecentApplicationsDialog.java中
  13. //new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME),0);
  14. 改成 new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME_FIRST),0);
  15. frameworks/policies/base/phone/com/android/internal/policy/impl/PhoneWindowManager.java中
  16. //mHomeIntent.addCategory(Intent.CATEGORY_HOME);
  17. 改成 mHomeIntent.addCategory(Intent.CATEGORY_HOME_FIRST);
  18. frameworks/policies/base/phone/com/android/internal/policy/impl/RecentApplicationsDialog.java中
  19. //ResolveInfo homeInfo = pm.resolveActivity(new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME),0);
  20. 改成 ResolveInfo homeInfo = pm.resolveActivity(newIntent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME_FIRST),0);

4) 寫一個自己的Launcher.
可以參考android sample中的Launcher,或者android源代碼中的 /packages/apps/Launcher 來寫。
在Launcher中標記其是不是Launcher的最關鍵的代碼時Manifest中的filter:android:name=”android.intent.category.HOME”
現在我們定義了自己的filter,那麼,我們在我們自己寫的Launcher中將Manifest改爲:

  1. <application android:process=”android.process.acore3″ android:icon=”@drawable/icon” android:label=”@string/app_name”>
  2. <activity android:name=”.FirstAppActivity”
  3. android:label=”@string/app_name”>
  4. <intent-filter>
  5. <action android:name=”android.intent.action.MAIN” />
  6. <category android:name=”android.intent.category.HOME_FIRST” />
  7. <category android:name=”android.intent.category.DEFAULT” />
  8. <category android:name=”android.intent.category.MONKEY” />
  9. </intent-filter>
  10. </activity>
  11. </application>

然後將編譯好的apk放到/out/target/product/generic/system/app目錄下。

5)將Android自帶的Launcher刪除掉,包括源代碼(packages/apps/Launcher)和apk(/out/target/product/generic/system/app/Launcher.apk)。

6)
做完這些工作,就可以重新編譯Android了,我們可以編譯修改過的幾個相關的包。
如果之前編譯過了Android源碼,可以用mmm命令來編譯部分的改動。
這裏需要這樣編譯:

  1. $ . build/envsetup.sh
  2. $ mmm frameworks/base
  3. $ mmm frameworks/base/services/java
  4. $ mmm frameworks/policies/base/mid
  5. $ mmm frameworks/policies/base/phone

7)
編譯完成後重新生成img文件。

  1. $ make snod

現在可以啓動Android模擬器來看效果了。
首先設置環境變量:
$ export ANDROID_PRODUCT_OUT= ./out/target/product/generic
然後切換到
$ cd ./out/host/linux-x86/bin
運行
$ ./emulator

這樣我們啓動的模擬器裏面用的image就是我們剛纔編譯好的自己定製的東西了。
從模擬器上可以看到啓動的Launcher是我們自己的Launcher,不會出現默認的Launcher了,也不會出現選擇界面。

9)我們再驗證一下,如果用戶裝上了一個其他的Launcher(Home)會怎麼樣。
從網上找一個一般的Launcher或者自己寫一個一般的Launcher裝上去,重新啓動,不會出現選擇界面。
按HOME鍵也不會出來兩個HOME來選擇。

這樣我們就牢牢控制了用戶的桌面。
只有我們自己定製的HOME才能裝上。 這對於定製Android設備的廠商很有用處。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章