Android系統之路(初識MTK) ------ (詳細精華)添加客供系統壁紙去除系統動態壁紙/Camera默認fine/remove android beam

① the first one


進入Camera 設置裏面默認 Video quality 攝錄像fine 1920*1088 使用 eclipse Dump view hierarchy for ui automator 工具捕獲要索引的關鍵字,關於Dump view hierarchy for ui 

automator 工具的使用問題,不懂的可以留言,索引關鍵字以及 Linux find cmd 得到相關關聯的資源文件,我們來看看這些文件的關係


packages\apps\Camera\res\values\array.xml  Note that the parameters pref_video_quality_entryvalues

 

<strong><span style="color:#3366ff;">    <!-- Camera Preferences Video Quality entries -->
    <string-array name="pref_video_quality_entries" translatable="false">
        <item>@string/pref_video_quality_entry_low_cam</item>
        <item>@string/pref_video_quality_entry_medium_cam</item>
        <item>@string/pref_video_quality_entry_high_cam</item>
        <item>@string/pref_video_quality_entry_fine_cam</item>
        <item>@string/pref_video_quality_entry_fine_4k2k</item>
        <item>@string/pref_video_quality_entry_1080p</item>
    </string-array>
    <string-array name="pref_video_quality_entryvalues" translatable="false">
        <!-- The integer value of CamcorderProfileEx.QUALITY_LOW -->
        <item>108</item>
         <!-- The integer value of CamcorderProfileEx.QUALITY_MEDIUM -->
        <item>109</item>
        <!-- The integer value of CamcorderProfileEx.QUALITY_HIGH -->
        <item>110</item>
        <!-- The integer value of CamcorderProfileEx.QUALITY_FINE -->
        <item>111</item>
        <!-- The integer value of CamcorderProfileEx.QUALITY_FINE_4k2k -->
        <item>123</item>
        <!-- The integer value of CamcorderProfileEx.QUALITY_1080P -->
        <item>118</item>
    </string-array></span></strong>


這兩個 array 其實就是對應關係,那我們只需要設置一個默認的 key 即可,具體在哪裏設置這個key呢?我們繼續往下!

packages\apps\Camera\res_ext\values\string.xmlNote that the parameters pref_video_record_quality_default

<strong><span style="color:#3366ff;"><string name="pref_video_record_quality_default" translatable="false">110</string></span></strong>

這裏 setttings default value is 110 , 改成 111 即設置開機系統默認攝錄像 fine ,make -jxx 工程,xx線程數,燒錄固件,效果如下


② the second

移除系統自帶壁紙,包括動態壁紙和靜態的,添加所有客供的壁紙,並且在 luncher3 長按 home 可以顯示

首先我們要去掉動態壁紙,靜態的在我這個項目上只有一張,之前博客已經講了

device/mediatek/$你的項目名稱/ProjectConfig.mk中的


MTK_LIVEWALLPAPER_APP = yes
MTK_LIVE_PHOTO_SUPPORT = yes
修改爲
MTK_LIVEWALLPAPER_APP = no
MTK_LIVE_PHOTO_SUPPORT = no

個別可能因爲平臺不同,具體文件所在也不同,但是索引上述關鍵字也可查找到相關設置,好,剛剛我們已經完成了第一步,現在走第二步

動態壁紙所在 package 爲  LiveWallpapers,所以只要你知道編譯系統的工作原理以及mk的相關配置,就知道怎麼去查找自己要得文件,我使用命令查找關鍵字

原始壁紙圖:



找到了這個mk文件,接下來只需要把我們的mk編譯命令加#註釋掉即可,註釋如下:

<strong><span style="color:#3366ff;"># Engineer-Jsp add remove system livewallpaper
#ifeq ($(strip $(MTK_LIVEWALLPAPER_APP)), yes)
#  PRODUCT_PACKAGES += LiveWallpapers
#  PRODUCT_PACKAGES += LiveWallpapersPicker
#  PRODUCT_PACKAGES += MagicSmokeWallpapers
#  PRODUCT_PACKAGES += VisualizationWallpapers
#  PRODUCT_PACKAGES += Galaxy4
#  PRODUCT_PACKAGES += HoloSpiralWallpaper
#  PRODUCT_PACKAGES += NoiseField
#  PRODUCT_PACKAGES += PhaseBeam
#endif</span></strong>

這裏我們已經把系統動態壁紙去掉了,接下來就是添加客供壁紙到 launcher3 ,這裏其實開始的時候我也沒有思路,我是根據系統原生 launcher3 AndroidMainfest.xml 分析出

來的,關於壁紙添加的函數

WallpaperPickerActivity extends WallpaperCropActivity 相關處理就在 WallpaperPickerActivity 類 ,WallpaperPickerActivity 有一個 init 函數,init 函數重要信息

<strong><span style="color:#3366ff;">    // called by onCreate; this is subclassed to overwrite WallpaperCropActivity
    protected void init() {
        setContentView(R.layout.wallpaper_picker);
......
        // Populate the built-in wallpapers
        ArrayList<WallpaperTileInfo> wallpapers = findBundledWallpapers();// 我們要找的關鍵函數
        mWallpapersView = (LinearLayout) findViewById(R.id.wallpaper_list);
        SimpleWallpapersAdapter ia = new SimpleWallpapersAdapter(this, wallpapers);
        populateWallpapersFromAdapter(mWallpapersView, ia, false);

        // Populate the saved wallpapers
......
    }</span></strong>

findBundledWallpapers() 函數


<strong><span style="color:#3366ff;">    private ArrayList<WallpaperTileInfo> findBundledWallpapers() {
        final PackageManager pm = getPackageManager();
        // 保存 WallpaperTileInfo 的集合
        final ArrayList<WallpaperTileInfo> bundled = new ArrayList<WallpaperTileInfo>(24);
        // 獲取單例 partner實例對象
        Partner partner = Partner.get(pm);
        if (partner != null) {
            final Resources partnerRes = partner.getResources();
            // getIdentifier 機制加載res文件,但是 Partner.RES_WALLPAPERS並不存在,所以我們跳過該段
            final int resId = partnerRes.getIdentifier(Partner.RES_WALLPAPERS, "array",
                    partner.getPackageName());
            ......
        }

        Pair<ApplicationInfo, Integer> r = getWallpaperArrayResourceId();//主要加載資源在該處
        if (r != null) {
            try {
                Resources wallpaperRes = getPackageManager().getResourcesForApplication(r.first);
                addWallpapers(bundled, wallpaperRes, r.first.packageName, r.second);// 加載壁紙資源的函數
            } catch (PackageManager.NameNotFoundException e) {
            }
        }

        if (partner == null || !partner.hideDefaultWallpaper()) {
            // Add an entry for the default wallpaper (stored in system resources)
            WallpaperTileInfo defaultWallpaperInfo =
                    (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT)
                    ? getPreKKDefaultWallpaperInfo()
                    : getDefaultWallpaper();
            if (defaultWallpaperInfo != null) {
                bundled.add(0, defaultWallpaperInfo);
            }
        }
        return bundled;
    }</span></strong>



Partner.RES_WALLPAPERS

<strong><span style="color:#3366ff;">public class Partner {

    static final String TAG = "Launcher.Partner";

    /** Marker action used to discover partner */
    private static final String
            ACTION_PARTNER_CUSTOMIZATION = "com.android.launcher3.action.PARTNER_CUSTOMIZATION";

    public static final String RES_FOLDER = "partner_folder";
    public static final String RES_WALLPAPERS = "partner_wallpapers";// partner_wallpapers
......</span></strong>


getWallpaperArrayResourceId() 函數

<strong><span style="color:#3366ff;">    public Pair<ApplicationInfo, Integer> getWallpaperArrayResourceId() {
        // Context.getPackageName() may return the "original" package name,
        // com.android.launcher3; Resources needs the real package name,
        // com.android.launcher3. So we ask Resources for what it thinks the
        // package name should be.
        final String packageName = getResources().getResourcePackageName(R.array.wallpapers);
        try {
            ApplicationInfo info = getPackageManager().getApplicationInfo(packageName, 0);
            return new Pair<ApplicationInfo, Integer>(info, R.array.wallpapers);
        } catch (PackageManager.NameNotFoundException e) {
            return null;
        }
    }</span></strong>

getWallpaperArrayResourceId() 函數加載了一個 array ,索引這個array,他確實是存在的,下面我們繼續看

addWallpapers(x,x,x,x)函數

<strong><span style="color:#3366ff;">    private void addWallpapers(ArrayList<WallpaperTileInfo> known, Resources res,
            String packageName, int listResId) {
        final String[] extras = res re.getStringArray(listResId);
        for (String extra : extras) {
            int resId = res.getIdentifier(extra, "drawable", packageName);
            if (resId != 0) {
                final int thumbRes = res.getIdentifier(extra + "_small", "drawable", packageName);

                if (thumbRes != 0) {
                    ResourceWallpaperInfo wallpaperInfo =
                            new ResourceWallpaperInfo(res, resId, res.getDrawable(thumbRes));
                    known.add(wallpaperInfo);
                    // Log.d(TAG, "add: [" + packageName + "]: " + extra + " (" + res + ")");
                }
            } else {
                Log.e(TAG, "Couldn't find wallpaper " + extra);
            }
        }
    }</span></strong>

addWallpapers(x,x,x,x)函數拿到 Resources 對象後,隨即取出它的每一個子項保存在 String[] ,遍歷每一個資源文件的對應name,通過Identifier機制獲取 resID,但是在後面又

執行了

<strong><span style="color:#3366ff;">final int thumbRes = res.getIdentifier(extra + "_small", "drawable", packageName);

                if (thumbRes != 0) {
                    ResourceWallpaperInfo wallpaperInfo =
                            new ResourceWallpaperInfo(res, resId, res.getDrawable(thumbRes));
                    known.add(wallpaperInfo);
                    // Log.d(TAG, "add: [" + packageName + "]: " + extra + " (" + res + ")");
                }</span></strong>
在獲得的資源名稱中後綴.png之前添加了 _small ,看到這我已經猜出代碼的用意了,然後判斷該資源文件id是否存在,存在即保存到info在保存到集合,下面解釋下添加後綴

_small 的用意,起始就是在我們長按系統 launcher 主界面之後,會彈出 wallpaper 和 widget 選項,當我們選擇壁紙之後,會看到一個水平划動得滾動跳,裏面有壁紙的縮略

圖,而_small就是縮略圖,而與之對應的不帶這個後綴的則是高清壁紙圖,於是我在 wallpapers array 添加了9張壁紙文件的名字,並且將圖片資源放進了對應的drawable-

xxxx文件中

wallpapers array:

<strong><span style="color:#3366ff;"><!--Engineer-Jsp add -->
<resources>
    <string-array name="wallpapers" translatable="false">
	<item>wallpaper_01</item>
	<item>wallpaper_02</item>
	<item>wallpaper_03</item>
	<item>wallpaper_04</item>
	<item>wallpaper_05</item>
	<item>wallpaper_06</item>
	<item>wallpaper_07</item>
	<item>wallpaper_08</item>
	<item>wallpaper_09</item>
    </string-array>
</resources></span></strong>

 剩下的就是製作縮略圖,但是縮略圖的大小我們是不知道的,所以要繼續查看代碼

在導出的系統原生 launcher code 中使用eclipse快捷鍵 ctrl+o(字母o),輸入get...看到 getDefaultThumbnailSize()函數,即意爲縮略圖的默認大小

getDefaultThumbnailSize()函數

<strong><span style="color:#3366ff;">    private static Point getDefaultThumbnailSize(Resources res) {
        return new Point(res.getDimensionPixelSize(R.dimen.wallpaperThumbnailWidth),
                res.getDimensionPixelSize(R.dimen.wallpaperThumbnailHeight));

    }</span></strong>

<strong><span style="color:#3366ff;"><resources>
<!-- Wallpaper picker -->
    <dimen name="wallpaperThumbnailWidth">106.5dp</dimen>
    <dimen name="wallpaperThumbnailHeight">94.5dp</dimen>
    <dimen name="wallpaperItemIconSize">32dp</dimen>
</resources></span></strong>

這樣就拿到了系統加載縮略圖的默認寬高了,接下來就是ps設置,因爲本人對ps是相當的精通,所以這裏我也介紹一下怎麼去編輯這個縮略圖,並且教你最傻瓜式的快捷鍵操

作,幾不到一分鐘就可以全部搞定

首先打開photoshop工具,ctrl+o(選擇要編輯的資源文件後回車)→ ctrl+alt+i (設置寬高後回車)→ ctrl+shift+s(另存爲原文件名字+“_samll”+.png)+回車 ,OK製作完成!



文件列表:


修改完畢之後 make clean 工程,在執行 make -jxx 編譯系統源碼,效果圖如下


③ remove system shared tiem Android Beam


這個看似似乎沒有難度,等到你自己去改的時候就不會這樣想了,不信你可以去試試,嘿嘿,當練手

那我就不介紹索引步驟了,反正關聯文件不再最上層,而是在源碼裏面,改的地方也是在源碼,我改之前也走過很多彎路,最後才糾正這個錯誤

那我就直接講我的改法吧,改之前的搜索努力就不提了,直接講改法,及常見錯誤

frameworks\base\core\java\android\widget\ActivityChooserView.java

ActivityChooserView 裏有一個內部類,即 ActivityChooserViewAdapter extends BaseAdapter 直接查看 getView()函數,因爲這裏是加載每一個ITEM的入口

<strong><span style="color:#3366ff;">        public View getView(int position, View convertView, ViewGroup parent) {
            final int itemViewType = getItemViewType(position);
            switch (itemViewType) {
                case ITEM_VIEW_TYPE_FOOTER: // 這裏的分支爲see all選項,默認 getcount+1 即最後一項,並且是 size>=5的情況下,這是系統做的自適應
                    if (convertView == null || convertView.getId() != ITEM_VIEW_TYPE_FOOTER) {
                        convertView = LayoutInflater.from(getContext()).inflate(
                                R.layout.activity_chooser_view_list_item, parent, false);
                        convertView.setId(ITEM_VIEW_TYPE_FOOTER);
                        TextView titleView = (TextView) convertView.findViewById(R.id.title);
                        titleView.setText(mContext.getString(
                                R.string.activity_chooser_view_see_all));
                    }
                    return convertView;
				// 我第一次修改的地方,也是第一次犯錯的地方	
                case ITEM_VIEW_TYPE_ACTIVITY:// 默認3個item顯示see all 如果size<5的情況下,see all 將隱藏,顯示所有item(<5的情況下)
				// 該處未被註釋之前,這是我走的第二個錯誤
//                	if(!activity.activityInfo.packageName.equals("com.android.nfc")){
                		if (convertView == null || convertView.getId() != R.id.list_item) {
                			convertView = LayoutInflater.from(getContext()).inflate(
                					R.layout.activity_chooser_view_list_item, parent, false);
                		}
                		PackageManager packageManager = mContext.getPackageManager();
                		// resolve.activityInfo.packageName ------ com.android.nfc
                		ResolveInfo activity = (ResolveInfo) getItem(position);
                		// Set the icon
                		ImageView iconView = (ImageView) convertView.findViewById(R.id.icon);
                		iconView.setImageDrawable(activity.loadIcon(packageManager));
                		// Set the title.
                		TextView titleView = (TextView) convertView.findViewById(R.id.title);
                		titleView.setText(activity.loadLabel(packageManager));
						// 這是我走的第一個錯誤,即阻止系統編譯該分享apk文件
                		// titleView.setText(activity.activityInfo.packageName); // 在這一塊我註釋掉了 label ,取而代之的是包名,因爲我打算把這個應用直接在 系統編譯之前,不編譯這個系統app
						// 取到的包名 com.android.nfc,之後執行命令,索引項目所在 project
                		// Highlight the default.
                		if (mShowDefaultActivity && position == 0 && mHighlightDefaultActivity) {
                			convertView.setActivated(true);
                		} else {
                			convertView.setActivated(false);
                		}
//                	}
                	return convertView;
                default:
                    throw new IllegalArgumentException();
            }</span></strong>

索引 package name


project name is Nfc ,那麼問題來了,我們怎麼取消系統編譯這個apk呢,繼續索引mk文件


編輯 mk 文件


註釋掉該處之後,使用抓包工具和在後臺查看發現nfc確實不存在了,但是令我不爽的是,Android Beam 分享子項依然還在!這就是我犯得第一個錯誤,後來我嘗試通過包名來

隱藏對應的position選項,但是出現了莫名的錯誤,同時出現了好幾個不見,然後下一次又是其他的不見,很奇怪,至今不知道原因,因爲我已經把限制條件寫死了!這是我犯

得第二個錯誤,於是乎我打算從BaseAdapter的原始加載數據模型下手,查看 ActivityChooserViewAdapter 這個內部類適配器,追朔如下函數

<strong><span style="color:#3366ff;">private ActivityChooserModel mDataModel;</span></strong>
<strong><span style="color:#3366ff;">        public void setDataModel(ActivityChooserModel dataModel) {
            Log.d(LOG_TAG, "ActivityChooserViewAdapter.setDataModel" +
                    ", dataModel = " + dataModel + ", isShown = " + isShown());

            ActivityChooserModel oldDataModel = mAdapter.getDataModel();
            if (oldDataModel != null && isShown()) {
                oldDataModel.unregisterObserver(mModelDataSetOberver);
            }
            mDataModel = dataModel;
            if (dataModel != null && isShown()) {
                dataModel.registerObserver(mModelDataSetOberver);
            }
            notifyDataSetChanged();
        }</span></strong>

<strong><span style="color:#3366ff;">        public int getCount() {
            int count = 0;
            int activityCount = mDataModel.getActivityCount();
            if (!mShowDefaultActivity && mDataModel.getDefaultActivity() != null) {
                activityCount--;
            }
            count = Math.min(activityCount, mMaxActivityCount);
            if (mShowFooterView) {
                count++;
            }
            return count;
        }</span></strong>

我繼續追朔 ActivityChooserModel.getDefaultActivity() 的函數,意圖在原始數據模型改變這個模型的內部結構

<strong><span style="color:#3366ff;">    /**
     * Gets the default activity, The default activity is defined as the one
     * with highest rank i.e. the first one in the list of activities that can
     * handle the intent.
     *
     * @return The default activity, <code>null</code> id not activities.
     *
     * @see #getActivity(int)
     */
    public ResolveInfo getDefaultActivity() {
        synchronized (mInstanceLock) {
            ensureConsistentState();
            if (!mActivities.isEmpty()) {
                return mActivities.get(0).resolveInfo;
            }
        }
        return null;
    }</span></strong>

ensureConsistentState()

<strong><span style="color:#3366ff;">    /**
     * Ensures the model is in a consistent state which is the
     * activities for the current intent have been loaded, the
     * most recent history has been read, and the activities
     * are sorted.
     */
    private void ensureConsistentState() {
        boolean stateChanged = loadActivitiesIfNeeded();
        stateChanged |= readHistoricalDataIfNeeded();
        pruneExcessiveHistoricalRecordsIfNeeded();
        if (stateChanged) {
            dumpActivities();// 我追朔的函數
            sortActivitiesIfNeeded();
            notifyChanged();
        }
    }</span></strong>

<strong><span style="color:#3366ff;">    /**
     * M: For debug. Dump activities associated with the current intent.
     */
    private void dumpActivities() {
        Log.d(LOG_TAG, "dumpActivities starts.");

        List<ActivityResolveInfo> activities = mActivities;//追朔 mActivities的add()函數
        final int activityCount = activities.size();
        for (int i = 0; i < activityCount; i++) {
            ActivityResolveInfo currentActivity = activities.get(i);
            Log.d(LOG_TAG, "  i = " + i + ", activity = " + currentActivity);
        }

        Log.d(LOG_TAG, "dumpActivities ends.");
    }</span></strong>


<strong><span style="color:#3366ff;">    /**
     * Loads the activities for the current intent if needed which is
     * if they are not already loaded for the current intent.
     *
     * @return Whether loading was performed.
     */
    private boolean loadActivitiesIfNeeded() {
        if (mReloadActivities && mIntent != null) {
            mReloadActivities = false;
            mActivities.clear();// 加載本次數據模型之前,清除掉之前的數據模型集
            List<ResolveInfo> resolveInfos = mContext.getPackageManager()
                    .queryIntentActivities(mIntent, 0);
            final int resolveInfoCount = resolveInfos.size();
            for (int i = 0; i < resolveInfoCount; i++) {// 循環讀取
                ResolveInfo resolveInfo = resolveInfos.get(i);
                ActivityInfo activityInfo = resolveInfo.activityInfo;
                if (ActivityManager.checkComponentPermission(activityInfo.permission,
                        android.os.Process.myUid(), activityInfo.applicationInfo.uid,
                        activityInfo.exported) == PackageManager.PERMISSION_GRANTED) { 判斷獲取該應用是否具備某一項權限
                	// Engineer-Jsp add remove system default share application com.android.nfc
                	if(android.os.SystemProperties.isWalPadVersion()){// 我在此處添加了我的限制模型條件,即 model 值 爲 walpad c 返回true 
                		if(!resolveInfo.activityInfo.packageName.equals("com.android.nfc")){// 包名不爲 com.android.nfc 時加載,這樣就可以剔除掉Android Beam,因爲ActivityChooser.ActivityChooserViewAdapter的getcount是根據模型而改變的
                			mActivities.add(new ActivityResolveInfo(resolveInfo));
                		}
                	}else{
                		mActivities.add(new ActivityResolveInfo(resolveInfo));
                	}
                }
            }
            Log.d(LOG_TAG, "loadActivitiesIfNeeded, activities updated, mIntent = " + mIntent);
            return true;
        }
        return false;
    }</span></strong>

改完代碼之後,重新make 工程,燒錄固件,效果如下:


因爲getcount<5,所以系統把see all 隱藏掉了,即最後一項(getcount+1)的查看所有可分享的子項

至此,今天所有分享的都已經分享完了,謝謝大家觀博

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