获取到所有的表盘信息
关于表盘的获取,网上的资料也少,也只是怎么获取当前壁纸(表盘)。这里呢,就从思路上尝试去获取表盘。
思路:原理上来讲,表盘就是一个服务,动态壁纸,在后台不断地刷新。这样子的话,我们可以通过获取所有的服务,添加过滤即获取表盘。
1、拿到包管理器
2、通过包管理器去获取所有的服务,但是要添加过滤
3、还是看码吧,已经定了注释,相信聪明的你一定可以的
private void getAllWallpapers() {
//拿到包管理器
final PackageManager mPackageManager = getPackageManager();
//获取到包管理器(第二个参数过代表过滤形式,过滤形式有两种,一种是Intent,一种是Resolved)
List<ResolveInfo> servicesLists = mPackageManager.queryIntentServices(new Intent(WallpaperService.SERVICE_INTERFACE),PackageManager.GET_META_DATA);
//获取到集合的长度
int size = servicesLists.size();
//创建一个用来保存壁纸信息的集合
mWallpaperInfos = new ArrayList<>(size);
//看看获取到的和手表上的表盘数量是否一样
Log.d(TAG, "size == " + size);
//遍历服务数据
for (int i = 0; i < size; i++) {
//集合内容
ResolveInfo resolveInfo = servicesLists.get(i);
//使用组件信息来创建壁纸服务,当然,也可以先不new,用的时候再New,反正已经获取到了嘛。
WallpaperInfo info;
try {
info = new WallpaperInfo(this, resolveInfo);
} catch (XmlPullParserException e) {
Log.w(TAG, "妈蛋,Xml解析错误... " + e.toString());
continue;
} catch (IOException e) {
Log.w(TAG, "妈蛋,IO异常呢.... " + e.toString());
continue;
}
//此处应有掌声.....
//把壁纸信息都添加到集合里头
mWallpaperInfos.add(info);
}
}
更换表盘
普通的壁纸切换的方法是公开的,权限的public的。
这是通过设置Bitmap的形式来设置壁纸
public void setBitmap(Bitmap bitmap) throws IOException {
....
}
这是通过设置流的形式来设置壁纸
public void setStream(InputStream data) throws IOException {
......
}
这是设置资源文件的形式来设置壁纸
public void setResource(@RawRes int resid) throws IOException {
.....
}
貌似就是这几个了哈,具体请看WallpaperManager这个类。
那么设置动态壁纸呢,是私有的,并且是隐藏的,并并且是系统的api。在WallpaperManager类里可以找到如下代码:
/**
* Set the live wallpaper.
* 设置动态壁纸
* This can only be called by packages with android.permission.SET_WALLPAPER_COMPONENT
* permission.
* 这只能被有更换权限的包(app)调用。
* @hide(隐藏)
*/
@SystemApi(系统api)
public boolean setWallpaperComponent(ComponentName name) {
if (sGlobals.mService == null) {
Log.w(TAG, "WallpaperService not running");
return false;
}
try {
sGlobals.mService.setWallpaperComponentChecked(name, mContext.getOpPackageName());
return true;
} catch (RemoteException e) {
// Ignore
}
return false;
}
这个方法是隐藏的,我们可以通过反射方法去调用,参数嘛,前面我们已经准被好了表盘的信息,只有小手一抖就可以获取到ComponentName了。
ComponentName component = wallpaperInfo.getComponent();
重点来了:这个方法有Android Wear里有,也就是用模拟器的时候,可以获取到这个方法。但是,在百度的系统更里头,获取不到,会报NoSuchMethodException异常。
所以,我们在百度系统里就不能用这种方法了。可能它阉割掉了。反正实验结果就是:Android Wear原生系统可以获取到这个方法,而百度的系统上获取不到。
我们看看setWallpaperComponent这个方法它做了什么事呢?其实它呢,核心代码就一句:
sGlobals.mService.setWallpaperComponentChecked(name, mContext.getOpPackageName());
这里的mService是何方神圣呢?点进去看一看!
private IWallpaperManager mService;
原来这个mService是IwallpapaerManager,看到这里应该很熟悉了吧,是吧。这肯定是一个接口,它呢,用于连接修改表盘的服务。
更进一步来说,我们不通过上面这个方法来设置壁纸,直接使用接口里的方法来设置。接口的源码如下:
/** @hide */
interface IWallpaperManager {
......
/**
* Set the live wallpaper.
*/
void setWallpaperComponent(in ComponentName name);
........
}
它还是hide的,同理通过反射就可以获取到了是吧,然后就可以设置动态壁纸啦!
这个在百度的duware系统上可以哈,亲测可用!
/*这里通过反射,去获取到这个getIWallpaperManager()的方法,返回一个IWallpaperManager实例
后面作为实例扔到invoke里头。
*/
receiver = (IWallpaperManager) mWallpaperManager
.getClass()
.getMethod("getIWallpaperManager", new Class[0])
.invoke(mWallpaperManager, new Object[0]);
/*这里通过反射获取到setWallpaperComponent方法,来设置壁纸,实例对象就是这玩意啦*/
Class.forName("android.app.IWallpaperManager")
.getMethod("setWallpaperComponent", new Class[]{ComponentName.class})
.invoke(receiver, new Object[]{component});
好啦,到这里的话,你以为设置动态壁纸就搞定了,不是的哈,还有权限呢?
设置壁纸的权限
前面我们也看到了,修改动态壁纸是系统的API,也就是说这个需要系统的权限,在这个app的配置文件里添加了权限,还不行呢。还要对它进行系统签名,才真正有这样的权限去修改动态壁纸。
<uses-permission android:name="android.permission.SET_WALLPAPER_COMPONENT"/>
在配置文件里添加这个权限,我们可以看源码嘛,第一句话就是检查权限:
public void setWallpaperComponent(ComponentName name) {
checkPermission(android.Manifest.permission.SET_WALLPAPER_COMPONENT);
synchronized (mLock) {
if (DEBUG) Slog.v(TAG, "setWallpaperComponent name=" + name);
int userId = UserHandle.getCallingUserId();
WallpaperData wallpaper = mWallpaperMap.get(userId);
if (wallpaper == null) {
throw new IllegalStateException("Wallpaper not yet initialized for user " + userId);
}
final long ident = Binder.clearCallingIdentity();
try {
wallpaper.imageWallpaperPending = false;
bindWallpaperComponentLocked(name, false, true, wallpaper, null);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
}
有了权限之后,我们还需要进行系统签名,步骤如下:
1、生成APK,是APK就行了,有沒有签名都可以;
2、准备好这几个文件:
其中,第一第二个是秘钥文件,这是系统的签名文件,这里的话,它是百度系统的签名。也就是说
用它签名后,就有权限在百度系统上的权限。但是,在Android Wear原生系统上是用不了哦!
然后,把APK复制到上面文件的文件夹里头,然后打开CMD,切换到上面文件夹下:
执行: java -jar signapk.jar platform..x509.pem plantform.pk8 应用名字.apk 签名后的名字.apk
好啦,到这里的话,就可以了。