Android系統(tǒng)定制機原廠直接設(shè)置上網(wǎng)參數(shù)無需另行設(shè)置。(上述內(nèi)容僅適用于廣東聯(lián)通用戶)
成都創(chuàng)新互聯(lián)企業(yè)建站,十多年網(wǎng)站建設(shè)經(jīng)驗,專注于網(wǎng)站建設(shè)技術(shù),精于網(wǎng)頁設(shè)計,有多年建站和網(wǎng)站代運營經(jīng)驗,設(shè)計師為客戶打造網(wǎng)絡(luò)企業(yè)風(fēng)格,提供周到的建站售前咨詢和貼心的售后服務(wù)。對于成都網(wǎng)站制作、網(wǎng)站建設(shè)中不同領(lǐng)域進行深入了解和探索,創(chuàng)新互聯(lián)在網(wǎng)站建設(shè)中充分了解客戶行業(yè)的需求,以靈動的思維在網(wǎng)頁中充分展現(xiàn),通過對客戶行業(yè)精準市場調(diào)研,為客戶提供的解決方案。
1.客制應(yīng)用需要直接打開藍牙界面的接口,Android R里面默認沒有所以重新添加一個
Index: packages/apps/Settings/AndroidManifest.xml
===================================================================
--- packages/apps/Settings/AndroidManifest.xml (revision 11165)
+++ packages/apps/Settings/AndroidManifest.xml (revision 11166)
@@ -419,10 +419,10 @@
? ? ? ? ? ? action android:name="android.intent.action.MAIN" /
? ? ? ? ? ? category android:name="com.android.settings.SHORTCUT" /
? ? ? ? /intent-filter
-? ? ? ? ? ? meta-data android:name="com.android.settings.FRAGMENT_CLASS"
+ meta-data android:name="com.android.settings.FRAGMENT_CLASS"
? ? ? ? ? ? android:value="com.android.settings.connecteddevice.ConnectedDeviceDashboardFragment" /
? ? /activity-alias
-
+
? ? !-- Keep compatibility with old shortcuts. --
? ? activity-alias android:name=".bluetooth.BluetoothSettings"
? ? ? ? ? ? ? ? ? ? android:label="@string/devices_title"
@@ -3192,6 +3192,21 @@
? ? ? ? meta-data android:name="com.android.settings.PRIMARY_PROFILE_CONTROLLED"
? ? ? ? ? ? ? ? ? ? android:value="true" /
? ? /activity
+
+ !----
+ activity
+? ? ? ? ? ? android:name="Settings$BluetoothConnectActivity"
+? ? ? ? ? ? android:label="@string/bluetooth_settings_title"
+? ? ? ? ? ? intent-filter android:priority="1"
+? ? ? ? ? ? ? ? action android:name="com.android.settings.BLUETOOTH_CONNECT_SETTINGS" /
+? ? ? ? ? ? ? ? category android:name="android.intent.category.DEFAULT" /
+? ? ? ? ? ? /intent-filter
+? ? ? ? ? ? meta-data android:name="com.android.settings.FRAGMENT_CLASS"
+? ? ? ? ? ? ? ? android:value="com.android.settings.connecteddevice.BluetoothDashboardFragment" /
+ meta-data android:name="com.android.settings.PRIMARY_PROFILE_CONTROLLED"
+? ? ? ? ? ? ? ? ? ? ? android:value="true" /
+? ? ? ? /activity
+
? ? activity android:name="Settings$BluetoothDeviceDetailActivity"
? ? ? ? ? ? ? android:label="@string/device_details_title"
Index: packages/apps/Settings/src/com/android/settings/dashboard/DashboardFragmentRegistry.java
===================================================================
--- packages/apps/Settings/src/com/android/settings/dashboard/DashboardFragmentRegistry.java (revision 11165)
+++ packages/apps/Settings/src/com/android/settings/dashboard/DashboardFragmentRegistry.java (revision 11166)
@@ -44,6 +44,7 @@
import com.android.settings.security.LockscreenDashboardFragment;
import com.android.settings.security.SecuritySettings;
import com.android.settings.system.SystemDashboardFragment;
+import com.android.settings.connecteddevice.BluetoothDashboardFragment;
import com.android.settingslib.drawer.CategoryKey;
import java.util.Map;
@@ -75,6 +76,8 @@
? ? ? ? ? ? CategoryKey.CATEGORY_CONNECT);
? ? PARENT_TO_CATEGORY_KEY_MAP.put(AdvancedConnectedDeviceDashboardFragment.class.getName(),
? ? ? ? ? ? CategoryKey.CATEGORY_DEVICE);
+? ? ? ? PARENT_TO_CATEGORY_KEY_MAP.put(BluetoothDashboardFragment.class.getName(),
+? ? ? ? ? ? ? ? CategoryKey.CATEGORY_BLUETOOTH);
? ? PARENT_TO_CATEGORY_KEY_MAP.put(AppAndNotificationDashboardFragment.class.getName(),
? ? ? ? ? ? CategoryKey.CATEGORY_APPS);
? ? PARENT_TO_CATEGORY_KEY_MAP.put(PowerUsageSummary.class.getName(),
Index: packages/apps/Settings/src/com/android/settings/core/SubSettingLauncher.java
===================================================================
--- packages/apps/Settings/src/com/android/settings/core/SubSettingLauncher.java (revision 11165)
+++ packages/apps/Settings/src/com/android/settings/core/SubSettingLauncher.java (revision 11166)
@@ -29,6 +29,7 @@
import com.android.settings.SettingsActivity;
import com.android.settings.SubSettings;
+import android.util.Log;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
public class SubSettingLauncher {
@@ -148,13 +149,11 @@
? ? ? ? throw new IllegalArgumentException("Destination fragment must be set");
? ? }
? ? intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT, mLaunchRequest.destinationName);
-
? ? if (mLaunchRequest.sourceMetricsCategory 0) {
? ? ? ? throw new IllegalArgumentException("Source metrics category must be set");
? ? }
? ? intent.putExtra(MetricsFeatureProvider.EXTRA_SOURCE_METRICS_CATEGORY,
? ? ? ? ? ? mLaunchRequest.sourceMetricsCategory);
-
? ? intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_ARGUMENTS, mLaunchRequest.arguments);
? ? intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_TITLE_RES_PACKAGE_NAME,
? ? ? ? ? ? mLaunchRequest.titleResPackageName);
Index: packages/apps/Settings/src/com/android/settings/core/gateway/SettingsGateway.java
===================================================================
--- packages/apps/Settings/src/com/android/settings/core/gateway/SettingsGateway.java (revision 11165)
+++ packages/apps/Settings/src/com/android/settings/core/gateway/SettingsGateway.java (revision 11166)
@@ -62,6 +62,7 @@
import com.android.settings.bluetooth.BluetoothDeviceDetailsFragment;
import com.android.settings.bugreporthandler.BugReportHandlerPicker;
import com.android.settings.connecteddevice.AdvancedConnectedDeviceDashboardFragment;
+import com.android.settings.connecteddevice.BluetoothDashboardFragment;
import com.android.settings.connecteddevice.ConnectedDeviceDashboardFragment;
import com.android.settings.connecteddevice.PreviouslyConnectedDeviceDashboardFragment;
import com.android.settings.connecteddevice.usb.UsbDetailsFragment;
@@ -168,6 +169,7 @@
? */
public static final String[] ENTRY_FRAGMENTS = {
? ? ? ? AdvancedConnectedDeviceDashboardFragment.class.getName(),
+? ? ? ? ? ? BluetoothDashboardFragment.class.getName(),
? ? ? ? CreateShortcut.class.getName(),
? ? ? ? WifiSettings.class.getName(),
? ? ? ? WifiSettings2.class.getName(),
Index: packages/apps/Settings/src/com/android/settings/Settings.java
===================================================================
--- packages/apps/Settings/src/com/android/settings/Settings.java (revision 11165)
+++ packages/apps/Settings/src/com/android/settings/Settings.java (revision 11166)
@@ -34,6 +34,7 @@
*/
public static class AssistGestureSettingsActivity extends SettingsActivity { /* empty */}
public static class BluetoothSettingsActivity extends SettingsActivity { /* empty */ }
+? ? public static class BluetoothConnectActivity extends SettingsActivity { /* empty */ }
public static class CreateShortcutActivity extends SettingsActivity { /* empty */ }
public static class FaceSettingsActivity extends SettingsActivity { /* empty */ }
public static class FingerprintSettingsActivity extends SettingsActivity { /* empty */ }
目的:
為了加強用戶體驗,增強品牌效應(yīng),使我們的產(chǎn)品有自己獨特的風(fēng)格,主題的定制將會是必然趨勢……
然而Android原生系統(tǒng)是不支持主題定制的,所以如何來定制主題,如何做得更好,需要大家集思廣益……
策略:
將介紹兩種定制主題的機制:
1.根據(jù)Android Configuration Qualifier機制,加入我們自己的JRDTheme定制。
2.用主題包的形式,根據(jù)用戶選擇不同的主題,而加載不同主題包中的資源。
基本原理:
首先介紹方式一:
Android Configuration Qualifier
Android 系統(tǒng)為一個項目提供了多套可供選擇的資源,通過命名特殊的資源文件夾來區(qū)別它們。系統(tǒng)在運行的時候,根據(jù)設(shè)備的當前配置為每個應(yīng)用加載合適的資源。
這些不同的資源都是放在每個應(yīng)用的res/目錄下面的,特殊的命名方式是-:
: 資源文件夾的名字,與默認資源文件夾保持一致
: 根據(jù)設(shè)備不同配置,需要使用的資源文件夾名字
Android系統(tǒng)根據(jù)優(yōu)先級的先后順序已經(jīng)支持多種Configuration Qualifier,如圖1:
如何添加 Jrd Theme Resources
JrdTheme 的核心策略是當我們設(shè)定了不同的主題后,會自動的替換我們想要替換的資源(FrameworkApp)。具體步驟如下:
1. 工程師從UE哪里獲得我們想要改變的主題資源,
2.把這些資源放到對應(yīng)模塊的res/目錄下,以Contacts模塊為例,假如我們想要定制drawable、color、layout。
原來在Contacts模塊中默認的資源目錄如下:
res/
layout/
main.xml
info.xml
drawable/
icon.png
values/
colors.xml
定制后的資源目錄如下:
res/
layout/
main.xml
info.xml
layout-jrdthemexxx/
main.xml
info.xml
drawable/
icon.png
drawable-jrdthemexxx/
icon.png
values/
colors.xml
values-jrdthemexxx/
colors.xml
Notes: jrdthemexxx 是其中一個 主題的 Qualifier,如果有多個主題,那么將會有多個jrdthemexxx存在。
3.與原來一樣編譯這些模塊,push到手機中即可。
這只是一個guide ,具體實現(xiàn)還要細化…… 目前在diablo、beetle上面已經(jīng)用這種方式實現(xiàn)了……我在smartiii上嘗試過,機制沒問題,但是改動的范圍太大了,比較麻煩。
方式二:
核心思想:系統(tǒng)中有多套主題資源包,并且應(yīng)用可以用相同的資源ID來訪問不同資源包中對應(yīng)的資源。 Android原生系統(tǒng)的資源訪問流程 對應(yīng)用來說,資源訪問主要有下面三種方
式:
第一、比較普遍的方式是使用xml定義,并且通過AAPT工具生成一個R文件,列出資源的索引來讓Android系統(tǒng)自己去遍歷整個資源樹的方式來訪問。
第二、通過Resources接口來訪問,使用Resources類的getDrawable、getString等接口來獲取資源。
第三、通過AssetManager類的接口去訪問,使用這個類的open方法來返回一個InputStream對象得到資源。
其實這三個訪問方式只是Android資源訪問中整個流程中在不同層次對外提供的三個接口,到底層的實現(xiàn)都是殊途同歸的。
因此我們實際上需要修改的部分主干是在訪問資源具體路徑前,按照當前系統(tǒng)主題設(shè)置訪問不同資源APK下的文件
即是把原生Android中資源ID和資源文件路徑之間一對一的關(guān)系改為一對多的關(guān)系。
例子如下:如果原有資源ID和資源文件路徑關(guān)系為:
R.drawable.image01 = 0x7F020001
通過系統(tǒng)的資源查找之后找到文件路徑為 /system/app/frameworks-res.apk下的res/drawable_hdpi/icon.png
在AssetManager native中去讀取資源并上傳。
那么我們需要做的是在傳入路徑去讀取資源時把文件路徑替換為/data/app/SystemTheme01.apk下的res/drawable_hdpi/icon.png
主要是里面的細節(jié)功能不同。原生只有基本功能。比方說查看wifi密碼,兒童模式,手勢操作,之類的不倫不類的功能都是定制的,還有定制的界面比較漂亮。原生沒有考慮美化。
深度定制的意思就是,加入了大量電信運營商的所謂特色服務(wù),其實就是你一碰就要錢的,而同時去掉了原生安卓系統(tǒng)的一些很有特色的東東,比如谷歌地圖、谷歌縱橫、狗狗talk、狗狗閱讀等,甚至連gmail都給你弄沒了。一般深度定制機很難刷機,如果沒有官方升級包就很難升級,因為其進入刷機模式的方法可能與原生安卓系機子有很大不同,或者根本就不告訴你。
果你要定制一個Android系統(tǒng),你想用你自己的Launcher(Home)作主界面來替換Android自己的Home,而且不希望用戶安裝的Launcher來替換掉你的Launcher.
我們可以通過修改Framework來實現(xiàn)這樣的功能。
這里以Android2.1的源代碼為例來實際說明。
1)首先了解一下Android的啟動過程。
Android系統(tǒng)的啟動先從Zygote開始啟動,然后......(中間的過程就不說了).....一直到了SystemServer(framework)這個地方,看到這段代碼:
/**
* This method is called from Zygote to initialize the system. This will cause the native
* services (SurfaceFlinger, AudioFlinger, etc..) to be started. After that it will call back
* up into init2() to start the Android services.
*/
native public static void init1(String[] args);
public static void main(String[] args) {
if (SamplingProfilerIntegration.isEnabled()) {
SamplingProfilerIntegration.start();
timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
SamplingProfilerIntegration.writeSnapshot("system_server");
}
}, SNAPSHOT_INTERVAL, SNAPSHOT_INTERVAL);
}
// The system server has to run all of the time, so it needs to be
// as efficient as possible with its memory usage.
VMRuntime.getRuntime().setTargetHeapUtilization(0.8f);
System.loadLibrary("android_servers");
init1(args);
}
public static final void init2() {
Log.i(TAG, "Entered the Android system server!");
Thread thr = new ServerThread();
thr.setName("android.server.ServerThread");
thr.start();
}
}
從SystemServer的main函數(shù)開始啟動各種服務(wù)。
首先啟動init1,然后啟動init2.
從上面的注釋可以看到:init1這個方法時被Zygote調(diào)用來初始化系統(tǒng)的,init1會啟動native的服務(wù)如SurfaceFlinger,AudioFlinger等等,這些工作做完以后會回調(diào)init2來啟動Android的service。
這里我們主要來關(guān)注init2的過程。
init2中啟動ServerThread線程,
ServerThread中啟動了一系列的服務(wù),比如這些:
ActivityManagerService
EntropyService
PowerManagerService
TelephonyRegistry
PackageManagerService
AccountManagerService
BatteryService
HardwareService
Watchdog
SensorService
BluetoothService
StatusBarService
ClipboardService
InputMethodManagerService
NetStatService
ConnectivityService
AccessibilityManagerService
NotificationManagerService
MountService
DeviceStorageMonitorService
LocationManagerService
SearchManagerService
FallbackCheckinService
WallpaperManagerService
AudioService
BackupManagerService
AppWidgetService
這些大大小小的服務(wù)起來以后,開始
((ActivityManagerService)ActivityManagerNative.getDefault()).systemReady()
在systemReady后開始開始啟動Launcher。
在尋找Launcher的時候是根據(jù)HOME的filter(在Manifest中定義的category android:name="android.intent.category.HOME" /)來過濾。
然后根據(jù)filter出來的HOME來啟動,如果只有一個HOME,則啟動這個HOME,如果用戶自己裝了HOME,那就會彈出來一個列表供用戶選擇。
我們現(xiàn)在希望從這里彈出我們自己定制的Launcher,同時也不希望彈出選擇HOME的界面,我們不希望用戶修改我們的home,比如我們的home上放了好多廣告,以及強制安裝的程序,不希望用戶把它干掉。
我們可以通過這樣來實現(xiàn):
2) 定義一個私有的filter選項,然后用這個選項來過濾HOME.
一般情況下我們使用Manifest中定義的category android:name="android.intent.category.HOME"來過濾的,我們現(xiàn)在增加一個私有的HOME_FIRST過濾。
在Intent.java(frameworks/base/core/java/android/content/Intent.java)中添加兩行代碼
//lixinso:添加CATEGORY_HOME_FIRST
@SdkConstant(SdkConstantType.INTENT_CATEGORY)
public static final String CATEGORY_HOME_FIRST = "android.intent.category.HOME_FIRST";
3)修改和CATEGORY_HOME相關(guān)的所有的地方,都改成HOME_FIRST,主要是framework中的這幾個地方:
frameworks/base/services/java/com/android/server/am/ActivityManagerService.java中
//intent.addCategory(Intent.CATEGORY_HOME);
改成intent.addCategory(Intent.CATEGORY_HOME_FIRST); //lixinso:
//if (r.intent.hasCategory(Intent.CATEGORY_HOME)) {
改成if (r.intent.hasCategory(Intent.CATEGORY_HOME_FIRST)) { //lixinso: Intent.CATEGORY_HOME - Intent.CATEGORY_HOME_FIRST
frameworks/base/services/java/com/android/server/am/HistoryRecorder.java中
// _intent.hasCategory(Intent.CATEGORY_HOME)
改成 _intent.hasCategory(Intent.CATEGORY_HOME_FIRST) //lixinso: Intent.CATEGORY_HOME-Intent.CATEGORY_HOME_FIRST
frameworks/policies/base/mid/com/android/internal/policy/impl/MidWindowManager.java中
//mHomeIntent.addCategory(Intent.CATEGORY_HOME);
改成 mHomeIntent.addCategory(Intent.CATEGORY_HOME_FIRST); //lixinso
frameworks/policies/base/mid/com/android/internal/policy/impl/RecentApplicationsDialog.java中
//new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME),0);
改成 new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME_FIRST),0); //lixinso
frameworks/policies/base/phone/com/android/internal/policy/impl/PhoneWindowManager.java中
//mHomeIntent.addCategory(Intent.CATEGORY_HOME);
改成 mHomeIntent.addCategory(Intent.CATEGORY_HOME_FIRST); //lixinso
frameworks/policies/base/phone/com/android/internal/policy/impl/RecentApplicationsDialog.java中
//ResolveInfo homeInfo = pm.resolveActivity(new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME),0);
改成 ResolveInfo homeInfo = pm.resolveActivity(new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME_FIRST),0); //lixinso
4) 寫一個自己的Launcher.
可以參考android sample中的Launcher,或者android源代碼中的 /packages/apps/Launcher 來寫。
在Launcher中標記其是不是Launcher的最關(guān)鍵的代碼時Manifest中的filter:android:name="android.intent.category.HOME"
現(xiàn)在我們定義了自己的filter,那么,我們在我們自己寫的Launcher中將Manifest改為:
application android:process="android.process.acore3" android:icon="@drawable/icon" android:label="@string/app_name"
activity android:name=".FirstAppActivity"
android:label="@string/app_name"
intent-filter
action android:name="android.intent.action.MAIN" /
category android:name="android.intent.category.HOME_FIRST" /
category android:name="android.intent.category.DEFAULT" /
category android:name="android.intent.category.MONKEY" /
/intent-filter
/activity
/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了,我們可以編譯修改過的幾個相關(guān)的包。
如果之前編譯過了Android源碼,可以用mmm命令來編譯部分的改動。
這里需要這樣編譯:
$ . build/envsetup.sh
$ mmm frameworks/base
$ mmm frameworks/base/services/java
$ mmm frameworks/policies/base/mid
$ mmm frameworks/policies/base/phone
7)
編譯完成后重新生成img文件。
$ make snod
8) 現(xiàn)在可以啟動Android模擬器來看效果了。
首先設(shè)置環(huán)境變量:
$ export ANDROID_PRODUCT_OUT= ./out/target/product/generic
然后切換到
$ cd ./out/host/linux-x86/bin
運行
$ ./emulator
這樣我們啟動的模擬器里面用的image就是我們剛才編譯好的自己定制的東西了。
從模擬器上可以看到啟動的Launcher是我們自己的Launcher,不會出現(xiàn)默認的Launcher了,也不會出現(xiàn)選擇界面。
9)我們再驗證一下,如果用戶裝上了一個其他的Launcher(Home)會怎么樣。
從網(wǎng)上找一個一般的Launcher或者自己寫一個一般的Launcher裝上去,重新啟動,不會出現(xiàn)選擇界面。
按HOME鍵也不會出來兩個HOME來選擇。