Androidのライブ壁紙をActivityから指定したい

アプリの一覧からアイコンを押したら、ライブ壁紙をプレビュー→壁紙に設定できる状態にできないかという話題。

ちなみに結論としてはパーミッション不足により失敗です。

ライブ壁紙の選択画面を表示させることはできるので、
Live Wallpaper – Binding an Activity to the ‘Open’ button of the market
こちらを参考にライブ壁紙選択画面の上にカスタムビューなどを表示させて誘導させるのが次善の策かと思います。

ライブ壁紙選択画面を表示するだけなら

Intent intent = new Intent(); 
intent.setAction(WallpaperManager.ACTION_LIVE_WALLPAPER_CHOOSER); 
startActivity(intent); 

でOK。

以下は失敗の記録。

上で書いたライブ壁紙選択画面表示のコードは 
LiveWallpaperをアプリから設定する方法を探ってみた|いろいろ備忘録

こちらの方法でも代替できます。

LiveWallpaperListActivityのソースコードを持ってきて追いかけてみることにしました。

LiveWallpaperListActivity.java

これを同じパッケージ内に設置して、layoutやdimen、color等を適当に用意してやることで、選択画面は同じ物を再現できます。

一応、用意したファイル

live_wallpaper_list.xml

<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="wrap_content" android:paddingLeft="6dip" android:paddingRight="6dip" android:paddingTop="6dip" android:paddingBottom="6dip" android:minHeight="?android:attr/listPreferredItemHeight"> 
<ListView android:id="@android:id/list" android:layout_width="fill_parent" android:layout_height="fill_parent" android:drawSelectorOnTop="false"/> 
<TextView android:id="@android:id/empty" android:layout_width="fill_parent" android:layout_height="fill_parent" android:gravity="center" android:visibility="gone" android:text="@string/live_wallpaper_empty" android:textAppearance="?android:attr/textAppearanceMedium"/> 
</LinearLayout>

live_wallpaper_entry.xml

<?xml version="1.0" encoding="utf-8"?> 
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="wrap_content" android:paddingLeft="6dip" android:paddingRight="6dip" android:paddingTop="6dip" android:paddingBottom="6dip" android:minHeight="?android:attr/listPreferredItemHeight"> 
<ImageView android:id="@+id/thumbnail" android:layout_width="@dimen/live_wallpaper_thumbnail_width" android:layout_height="@dimen/live_wallpaper_thumbnail_width" android:layout_gravity="center_vertical" android:scaleType="centerCrop"/> 
<LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="10dip" android:layout_marginRight="8dip" android:layout_centerVertical="true" android:layout_toRightOf="@id/thumbnail" android:orientation="vertical"> 
<TextView android:id="@+id/title_author" android:layout_width="fill_parent" android:layout_height="wrap_content" android:textAppearance="?android:attr/textAppearanceMedium" android:singleLine="true" android:ellipsize="marquee"/> 
<TextView android:id="@+id/description" android:layout_width="fill_parent" android:layout_height="wrap_content" android:textAppearance="?android:attr/textAppearanceSmall" android:maxLines="3"/> 
</LinearLayout> 
</RelativeLayout>

color.xml

<?xml version="1.0" encoding="utf-8"?> 
<resources> 
    <color name="live_wallpaper_thumbnail_background">#000000</color> 
    <color name="live_wallpaper_thumbnail_text_color">#ffffff</color> 
</resources>

dimens.xml (値は適当にいれた)

<?xml version="1.0" encoding="utf-8"?> 
<resources> 
    <dimen name="live_wallpaper_thumbnail_width">50dp</dimen> 
    <dimen name="live_wallpaper_thumbnail_height">50dp</dimen> 
    <dimen name="live_wallpaper_thumbnail_text_size">50dp</dimen> 
    <dimen name="live_wallpaper_thumbnail_text_offset">50dp</dimen> 
</resources>

で、このままでは

LiveWallpaperPreview.showPreview(this , REQUEST_PREVIEW, intent, info);

の行がコンパイルできないのでshowPreviewメソッド(staticメソッド)だけを取り出してきてLiveWallpaperListActivityに

	static final String EXTRA_LIVE_WALLPAPER_INTENT = "android.live_wallpaper.intent";
	static final String EXTRA_LIVE_WALLPAPER_SETTINGS = "android.live_wallpaper.settings";
	static final String EXTRA_LIVE_WALLPAPER_PACKAGE = "android.live_wallpaper.package";

	public void onItemClick(AdapterView<?> parent, View view, int position,
			long id) {
		final Intent intent = mWallpaperIntents.get(position);
		final WallpaperInfo info = mWallpaperInfos.get(position);
		//LiveWallpaperPreview.showPreview(this, REQUEST_PREVIEW, intent, info);
		//Intent preview = new Intent(this, LiveWallpaperPreview.class);
		String clazz = "com.android.wallpaper.livepicker.LiveWallpaperPreview";
		Intent preview = new Intent(Intent.ACTION_MAIN);
		int idx = clazz.lastIndexOf('.');
		String pkg = clazz.substring(0, idx);
		preview.setClassName(pkg, clazz);
		preview.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
		preview.putExtra(EXTRA_LIVE_WALLPAPER_INTENT, intent);
		preview.putExtra(EXTRA_LIVE_WALLPAPER_SETTINGS,
				info.getSettingsActivity());
		preview.putExtra(EXTRA_LIVE_WALLPAPER_PACKAGE, info.getPackageName());
		this.startActivityForResult(preview, REQUEST_PREVIEW);
	}

先程のサイトを参考に、こんな感じで書き換え。で、実行。

FATAL EXCEPTION: main 
java.lang.SecurityException: Permission Denial: starting Intent { act=android.intent.action.MAIN flg=0x10000000 cmp=com.android.wallpaper.livepicker/.LiveWallpaperPreview (has extras) } from ProcessRecord{4073a338 8432:com.sample.android.TestCase/10077} (pid=8432, uid=10077) requires null 
    at android.os.Parcel.readException(Parcel.java:1322) 
    at android.os.Parcel.readException(Parcel.java:1276) 
    at android.app.ActivityManagerProxy.startActivity(ActivityManagerNative.java:1351) 
    at android.app.Instrumentation.execStartActivity(Instrumentation.java:1374) 
    at android.app.Activity.startActivityForResult(Activity.java:2827) 
    at com.sample.android.TestCase.LiveWallpaperListActivity.onItemClick(LiveWallpaperListActivity.java:201) 
    at android.widget.AdapterView.performItemClick(AdapterView.java:284) 
    at android.widget.ListView.performItemClick(ListView.java:3513) 
    at android.widget.AbsListView$PerformClick.run(AbsListView.java:1812) 
    at android.os.Handler.handleCallback(Handler.java:587) 
    at android.os.Handler.dispatchMessage(Handler.java:92) 
    at android.os.Looper.loop(Looper.java:130) 
    at android.app.ActivityThread.main(ActivityThread.java:3683) 
    at java.lang.reflect.Method.invokeNative(Native Method) 
    at java.lang.reflect.Method.invoke(Method.java:507) 
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839) 
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597) 
    at dalvik.system.NativeStart.main(Native Method)

とりあえずライブ壁紙の一覧とアイコンは取れるってことはわかりましたね…


タグ: ,

新しく会社作りました!

コメント / トラックバック 4 件

  1. 通りすがり より:

    >ちなみに結論としてはパーミッション不足により失敗です。

    これは「LiveWallpaperをアプリから設定する方法を探ってみた|いろいろ備忘録 」さんの
    [このアクティビティは呼び出しかたがちょっと特殊で自分のスペックではどうにも解決不可能。。]
    の呼び出し方がわかって試した結果ですか? 
    それとも、LiveWallpaperPreview の処理と似たようななことをしてパーミッションでだめだった
    ということですか? 
    ちょっとこの辺りがわからなかったのでお答え頂けると幸いです。

  2. hotpi より:

    コメントありがとうございます。

    > これは「LiveWallpaperをアプリから設定する方法を探ってみた|いろいろ備忘録 」さんの
    > [このアクティビティは呼び出しかたがちょっと特殊で自分のスペックではどうにも解決不可能。。]
    > の呼び出し方がわかって試した結果ですか?

    多分「いろいろ備忘録」さんもshowPreviewメソッドの中身を見ていると思います。
    ですので、ご質問の前者は「呼び出し方がわかって試した結果」ですが、元々呼び出し方自体がわからなかったわけではないということです。

    > それとも、LiveWallpaperPreview の処理と似たようななことをしてパーミッションでだめだった
    > ということですか?

    そういうことです。
    exportedされていないActivityを自前のクラスから呼んでしまったためのエラーだと思いますが、これをやらなければコンパイルもできないのでここまで、ということになります。
    試行手順をメモした形です。
    もし解決手段が見つかったら教えていただけると幸いです。

  3. 心は萌え より:

    Androidをソースからコンパイルして確認しました。
    結論から言えば コンパイル自体はできますが
    最終的に
    android.permission.BIND_WALLPAPER
    android.permission.SET_WALLPAPER_COMPONENT
    の2つのパーミッションが 2.2以降 OSにより メーカー署名が必要 レベルになっている場合がほとんど。
    ということで 実際には エミュレーターでもないと動かせない。
    ライブ壁紙が設定できるのはメーカーアプリのみ。
    ということでFAみたいです。

    参考:http://blog.callas1900.net/2011/11/icsgingerbreadpermission.html
     

  4. hotpi より:

    なるほど、このパーミッションを与えるためには大抵の端末ではメーカー署名が必要ということなんですね。
    有益な情報ありがとうございます!

コメントをどうぞ