① 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>
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>
② 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>
来的,关于壁纸添加的函数
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>
<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>
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>
执行了
<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>
作,几不到一分钟就可以全部搞定
首先打开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>
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>
<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>
<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>
因为getcount<5,所以系统把see all 隐藏掉了,即最后一项(getcount+1)的查看所有可分享的子项
至此,今天所有分享的都已经分享完了,谢谢大家观博