万年素人からHackerへの道

万年素人がHackerになれるまで殴り書きするぜ。

  • ・資産運用おすすめ
    10万円は1000円くらい利益
    資産運用ブログ アセマネ
    • ・寄付お願いします
      YENTEN:YYzNPzdsZWqr5THWAdMrKDj7GT8ietDc2W
      BitZenny:ZfpUbVya8MWQkjjGJMjA7P9pPkqaLnwPWH
      c0ban:8KG95GXdEquNpPW8xJAJf7nn5kbimQ5wj1
      Skycoin:KMqcn7x8REwwzMHPi9fV9fbNwdofYAWKRo

    Unlockイベント

    BroadcastRecieverが必要?
    http://stackoverflow.com/questions/3462843/android-what-happens-when-device-is-unlocked
    http://d.hatena.ne.jp/eryngii_mori/20100520/1274357535

    原宿Android勉強会#15@THETERMINAL

    URL:http://atnd.org/events/26535
    Androidアプリ勉強したいので参加、常駐してアイコンが動的に変わるのを作りたかった
    Widget
    →ブロードキャストレシーバを使う。
    ・わかりやすい(日本語)
    http://www.techfirm.co.jp/lab/android/widget.html
    ・わかりやすい(英語)
    http://www.vogella.de/articles/AndroidWidgets/article.html

    →日本語の解説
    1.3. Register Widget(ウィジットの登録)
    AppWidgetをAndroidManifest.xmlのタグ内へ登録します。

    ・AndroidManifest.xml(あとの3でも全ソースが記載されている)

    <receiver
           android:icon="@drawable/icon"
           android:label="Example Widget"
           android:name="MyWidgetProvider" >
           <intent-filter >
                <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
           </intent-filter>
    
           <meta-data
              android:name="android.appwidget.provider"
              android:resource="@xml/widget_info" />
    </receiver>
    

    ※この時点で「widget_info」ではエラーが出るが、"3"で作るので気にしない。

    ・widget_info.xml(※3でまた書かれてます)
    ※resフォルダ内に「xml」フォルダを作成してその中へ配置
     右クリックメニューより、「新規」→「Android XML file」を選択。
     リソースの種類:AppWidget Provider

    <?xml version="1.0" encoding="utf-8"?>
    <appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
        android:initialLayout="@layout/widget_layout"
        android:minHeight="72dp"
        android:minWidth="146dp"
        android:updatePeriodMillis="180000"
    </appwidget-provider>
    

    ※layout/widget_layoutは後で作るので、「layout/widget_layout」がないぞっていうエラーは無視する。


    3. Example with fixed update interval(固定のアップデートインターバルの例)

    「/res/drawable-mdpi」に「myshape.xml」を作成する

    ・myshape.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <shape xmlns:android="http://schemas.android.com/apk/res/android"
        android:shape="rectangle">
        <stroke
            android:width="2dp"
            android:color="#FFFFFFFF" />
        <gradient
            android:angle="225"
            android:endColor="#DD2ECCFA"
            android:startColor="#DD000000" />
        <corners
            android:bottomLeftRadius="7dp"
            android:bottomRightRadius="7dp"
            android:topLeftRadius="7dp"
            android:topRightRadius="7dp" />
    </shape>
    

    「res/layout」に「widget_layout.xml」を作成する。
    ・widget_layout.xml

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_margin="8dip"
        android:background="@drawable/myshape" >
    
        <TextView
            android:id="@+id/update"
            style="@android:style/TextAppearance.Medium"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_gravity="center"
            android:gravity="center_horizontal|center_vertical"
            android:layout_margin="4dip"
            android:text="Static Text">
        </TextView>
    </LinearLayout>
    


    ・MyWidgetProvider.java
    ※「package com.shinriyo.widget;」はご自分の環境にあわせて適宜変更します。

    package com.shinriyo.widget;
    
    import java.util.Random;
    import android.app.PendingIntent;
    import android.appwidget.AppWidgetManager;
    import android.appwidget.AppWidgetProvider;
    import android.content.ComponentName;
    import android.content.Context;
    import android.content.Intent;
    import android.util.Log;
    import android.widget.RemoteViews;
    
    public class MyWidgetProvider extends AppWidgetProvider {
    
        // 使われない??
        private static final String ACTION_CLICK = "ACTION_CLICK";
    
        @Override
        public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
    
            // すべてのID取得
            ComponentName thisWidget = new ComponentName(context, MyWidgetProvider.class);
            int[] allWidgetIds = appWidgetManager.getAppWidgetIds(thisWidget);
            for (int widgetId : allWidgetIds) {
                // 乱数の生成
                int number = (new Random().nextInt(100));
    
                RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.widget_layout);
                Log.w("WidgetExample", String.valueOf(number));
                // テキストをセットする
                remoteViews.setTextViewText(R.id.update, String.valueOf(number));
    
                // onClickListenerの登録
                Intent intent = new Intent(context, MyWidgetProvider.class);
                intent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
                intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds);
    
                PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
                remoteViews.setOnClickPendingIntent(R.id.update, pendingIntent);
                appWidgetManager.updateAppWidget(widgetId, remoteViews);
            }
        }
    }
    

    ・AndroidManifest.xml もいじる

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="de.vogella.android.widget.example"
        android:versionCode="1"
        android:versionName="1.0" >
    
        <application
            android:icon="@drawable/icon"
            android:label="@string/app_name" >
            <receiver android:name="MyWidgetProvider" >
                <intent-filter >
                    <action 
                        android:name="android.appwidget.action.APPWIDGET_UPDATE" />
                </intent-filter>
    
                <meta-data
                    android:name="android.appwidget.provider"
                    android:resource="@xml/widget_info" />
            </receiver>
        </application>
    
        <uses-sdk android:minSdkVersion="8" />
    </manifest>
    


    『3までで取り敢えず起動はできます』
    動作内容:
    ホームを押しっぱなしで、起動→ウィジット→Example Widget
    ホームにでた青いグラデーションの四角を叩くと0〜99の数字が表示される。


    4から、先ほどの「MyWidgetProvider.java」の内部処理を「UpdateWidgetService.java」に分割します。


    4. Update via a service and onClickListener(サービスとオンクリックのリスナーによるアップデート)

    ・UpdateWidgetService.java 作成
    ※「package com.shinriyo.widget;」はご自分の環境にあわせて適宜変更します。

    package com.shinriyo.widget;
    
    import java.util.Random;
    import android.app.PendingIntent;
    import android.app.Service;
    import android.appwidget.AppWidgetManager;
    import android.content.ComponentName;
    import android.content.Intent;
    import android.os.IBinder;
    import android.util.Log;
    import android.widget.RemoteViews;
    
    public class UpdateWidgetService extends Service {
        private static final String LOG = "com.shinriyo.widget example";
    
        @Override
        public void onStart(Intent intent, int startId) {
            Log.i(LOG, "Called");
    
            AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(this.getApplicationContext());
    
            int[] allWidgetIds = intent.getIntArrayExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS);
    
            ComponentName thisWidget = new ComponentName(getApplicationContext(), MyWidgetProvider.class);
            int[] allWidgetIds2 = appWidgetManager.getAppWidgetIds(thisWidget);
            Log.w(LOG, "From Intent" + String.valueOf(allWidgetIds.length));
            Log.w(LOG, "Direct" + String.valueOf(allWidgetIds2.length));
    
            for (int widgetId : allWidgetIds) {
                // 乱数の生成
                int number = (new Random().nextInt(100));
    
                RemoteViews remoteViews = new RemoteViews(this .getApplicationContext().getPackageName(), R.layout.widget_layout);
                Log.w("WidgetExample", String.valueOf(number));
                // テキストをセットする
                remoteViews.setTextViewText(R.id.update, "Random: " + String.valueOf(number));
    
                // onClickListenerの登録
                Intent clickIntent = new Intent(this.getApplicationContext(), MyWidgetProvider.class);
    
                clickIntent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
                clickIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, allWidgetIds);
    
                PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 0, clickIntent, PendingIntent.FLAG_UPDATE_CURRENT);
                remoteViews.setOnClickPendingIntent(R.id.update, pendingIntent);
                appWidgetManager.updateAppWidget(widgetId, remoteViews);
            }
            stopSelf();
    
            super.onStart(intent, startId);
        }
    
        @Override
        public IBinder onBind(Intent intent) {
            return null;
        }
    }
    

    ・「AndroidManifest.xml」に次に作るJavaを登録しておく
    の間に記載する

    <service android:name=".UpdateWidgetService"></service>
    

    ・先程の「MyWidgetProvider」を修正する
    ※消したところと追加したところを記載しました

    package com.shinriyo.widget;
    
    //import java.util.Random;
    //import android.app.PendingIntent;
    import android.appwidget.AppWidgetManager;
    import android.appwidget.AppWidgetProvider;
    import android.content.ComponentName;
    import android.content.Context;
    import android.content.Intent;
    import android.util.Log;
    //import android.widget.RemoteViews;
    
    public class MyWidgetProvider extends AppWidgetProvider {
    
        // 使われない??
    //    private static final String ACTION_CLICK = "ACTION_CLICK";
        private static final String LOG = "com.shinriyo.widget example";
        
        @Override
        public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
    
            Log.w(LOG, "onUpdate method called"); // 追加
            // すべてのID取得
            ComponentName thisWidget = new ComponentName(context, MyWidgetProvider.class);
            int[] allWidgetIds = appWidgetManager.getAppWidgetIds(thisWidget);
    
            // 追加
            // サービスによりインテントの開始
            Intent intent = new Intent(context.getApplicationContext(), UpdateWidgetService.class);
            intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, allWidgetIds);
    
            // サービスによるウィジットのアップデート
            context.startService(intent);
    /*
            for (int widgetId : allWidgetIds) {
                // 乱数の生成
                int number = (new Random().nextInt(100));
    
                RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.widget_layout);
                Log.w("WidgetExample", String.valueOf(number));
                // テキストをセットする
                remoteViews.setTextViewText(R.id.update, String.valueOf(number));
    
                // onClickListenerの登録
                Intent intent = new Intent(context, MyWidgetProvider.class);
                intent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
                intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds);
    
                PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
                remoteViews.setOnClickPendingIntent(R.id.update, pendingIntent);
                appWidgetManager.updateAppWidget(widgetId, remoteViews);
            }
    */
        }
    }
    

    →動作:
    複数のウィジットが作成でき、1つのウィジットにタッチするとすべてのウィジットにランダムな数が反映される。

    ・細かい説明があるサイト(英語)
    http://blog.doityourselfandroid.com/2011/05/24/developing-android-home-screenwidgets/

    SQLAlchemyのわかりやすいところ

    →チュートリアル風になってる
    ・その1
    http://d.hatena.ne.jp/TaoPyPI/20090131/1233414685
    ・その2
    http://d.hatena.ne.jp/TaoPyPI/20090212/1234457633

    quicktigame2d

    Titanium用の2Dモジュール
    http://code.google.com/p/quicktigame2d/