ラベル Android SDK の投稿を表示しています。 すべての投稿を表示
ラベル Android SDK の投稿を表示しています。 すべての投稿を表示

2018年6月16日土曜日

[Android SDK] targetSdkVersion 26に変更したらRemoteViewsで例外が発生して対処

メモガキのtargetSdkVersionを24から26に変更する作業を進めていたら、ウィジェット設定画面でウィジェットのプレビューが表示され無い問題に気づきました。



となるところが、



上部のプレビューが消えてしまいました。
このウィジェットのプレビューは、AppWidgetHostViewを利用してActivity中にAppWidgetを表示するビューを作成しています。

Android StudioのLogcatを確認すると、
android.widget.RemoteViews$ActionException: view: android.support.v7.widget.AppCompatImageView can't use method with RemoteViews: setImageBitmap(class android.graphics.Bitmap)

と出力されているため、AppCompatImageViewがAppWidgetで使えないことが原因であることはすぐに気づきました。
どこかの処理で、ImageViewがAppCompatImageViewに置き換えられてしまったようです(レイアウトファイルは変更していないから)。

試行錯誤していたら、rv.applyに対してContextを指定している箇所を、Activity(AppCompatActivity)からApplicationContextに変更して解決しました。
AppWidgetHostView hostView;
RemoteViews rv;
rv.apply(getApplicationContext(), mPreviewWidget);

hostView.removeAllViews();
//View view = rv.apply(this, hostView);
View view = rv.apply(getApplicationContext(), hostView);
hostView.addView(view);

targetSdkVersionを変えた際にsupport.v4のバージョンも変更したから、AppCompatActivityの挙動が変わったようですね。

2013年10月9日水曜日

[Android SDK] ダイアログを自由にカスタマイズする

メモガキの日時設定画面はダイアログをカスタマイズして作成している。Dialogを継承して、onCreateをオーバライドしてsetContentViewを自由なレイアウトを指定します。タイトルバーや境界線を無くし、全画面表示にしています。


public class TestDialog extends Dialog {
 /* 〜〜〜 一部省略 〜〜〜*/
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);

                // タイトルバーを非表示にする
  requestWindowFeature(Window.FEATURE_NO_TITLE); 

  setContentView(R.layout.dlg_deadline);

                // ダイアログの背景(境界線)を無くす(透明)
  getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));

                // ダイアログの大きさ最大にする(任意のサイズも指定可能)
                getWindow().setLayout(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT);

 }
 /* 〜〜〜 一部省略 〜〜〜*/
}

2013年10月7日月曜日

[Android SDK] 動的に設定画面(Preference)を作成する

ほとんどのAndroidアプリには設定画面が用意されている。

(例:メモガキの設定画面)

こういった設定画面は、.xmlファイルに記述するケースが多いが動的にプログラミングで作成することもできる。
例えば、デバッグ時、AndroidOSのバージョンに応じて表示する設定項目の場合に使える。

1から作成する場合

まずは設定項目を作成するために、PreferenceManagerを取得する。
// For Activity
PreferenceManager PreferenceActivity::getPreferenceManager()

// For Fragment
PreferenceManager PreferenceFragment::getPreferenceManager()
PreferenceManagerで設定項目のルート項目を作成する。
PreferenceScreen PreferenceManager::createPreferenceScreen(Context context);
以降は、設定項目を作成して追加して行く。
// Context context;
PreferenceScreen root = getPreferenceManager().createPreferenceScreen(context);
PreferenceCategory category = new PreferenceCategory(context);
category.setTitle("Category");
root.addPreference(category);

PreferenceScreen item = getPreferenceManager().createPreferenceScreen(context);
item.setTitle("Item");
category.add(item);
最後に、設定画面に設定する。
// For Activity
// void PreferenceScreen::setPreferenceScreen(PreferenceScreen preferenceScreen)
// 
// For Fragment
// void PreferenceFragment::setPreferenceScreen(PreferenceScreen preferenceScreen)
//
setPreferenceScreen(root);

既存の設定画面に追加する場合

既存の設定項目のルート項目を取得する。
// For Activity
PreferenceScreen PreferenceActivity::getPreferenceScreen()

// For Fragment
PreferenceScreen PreferenceFragment::getPreferenceScreen()
取得したルート項目にさきほどと同様に追加していく。


参考までに

メモガキではアプリの更新履歴を、ファイル(res/raw)から更新履歴を情報を読み込み、動的に設定画面をベースに表示している。

public class RpNoteVersionFragment extends PreferenceListFragment {
 @Override
 public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setPreferenceScreen(createReleaseNote());
 }
 public PreferenceScreen createReleaseNote() {
  final Context c = getActivity();
  PreferenceScreen root = getPreferenceManager().createPreferenceScreen(c);
  
  BufferedReader reader = null;
  InputStream stream = null;
  String buffer = null;
  PreferenceCategory category = null;
  try {
   stream = c.getResources().openRawResource(R.raw.release_note);
   reader = new BufferedReader(new InputStreamReader(stream));
   while ((buffer = reader.readLine()) != null) {
    if (category == null) {
     category = new PreferenceCategory(c);
     category.setTitle(buffer);
     root.addPreference(category);
    } else if (buffer.equals("")) {
     category = null;
    } else {
     Preference item = new Preference(c);
     item.setTitle(buffer);
     item.setLayoutResource(R.layout.pref_single_item);
     category.addPreference(item);
    }
   }
  } catch (IOException ioe) {
   
  } finally {
   if (reader != null) {
    try {
     reader.close();
    } catch (IOException ioe) {}
   }
   if (stream != null) {
    try {
     stream.close();
    } catch (IOException ioe2) {}
   }
  }
  return root;
 }
}

// R.raw.release_noteの中身
Ver.0.3.0
Append text to an existing note with share.
Add icons of category.

Ver.0.2.0
Change an order of category display.

Ver.0.1.1
Display a widget, today's number of schedules. 

Ver.0.0.0
First version 

2012年11月13日火曜日

[Android SDK] 設定画面のレイアウトをカスタマイズする

Androidアプリには設定画面がつきものです。標準で設定画面を作るためのクラス(PreferenceActivity)が用意されており、XMLで設定項目を記述するだけで簡単に作れる。

ただ、設定画面のレイアウトをカスタマイズするには特殊なやり方が必要になります。

PreferenceActivityを継承してActivityを作るのは同じですが、setContentViewメソッドでレイアウトファイル(XML)を指定するところがポイント。
public class RpNotePreferenceActivity extends PreferenceActivity {
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.act_preference);
    addPreferencesFromResource(R.xml.preference);
  }
}

単純にレイアウトファイル(XML)を作成するだけではダメで、設定画面に置き換えるListViewを「android:id="@android:id/list"」属性付きで追加する必要があります。
簡単な例ですと次のようにすると、
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:ads="http://schemas.android.com/apk/lib/com.google.ads"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical"
    tools:context=".activity.RpNotePreferenceActivity" >

    <ListView
        android:id="@android:id/list"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_weight="1" />
 <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:gravity="center_horizontal">
  <Button
      android:id="@+id/button1"
      android:layout_width="fill_parent"
      android:layout_height="wrap_content"
      android:text="Button" />
    </LinearLayout>
</LinearLayout>

こんな感じで、画面下側にボタンがあるような設定画面が作れます(実際には、リストが設定項目に置き換わります)。

試してみてください。

2012年11月12日月曜日

[Android SDK] ImageViewを最前面にフローティングさせる

ドラッグ可能なリストビューを作成する過程で、ドラッグ中のアイテムを最前面でフローティングさせるのに苦労しましたので、そのやり方を記載します。
★オレンジ色の浮いているやつです。


実際は、ドラッグ対象のアイテムをBitmap化として、ImageViewで最前面に表示しています。

1.ViewをBitmapに変換する

たとえば、ListViewであれば、getChildAtでアイテムをViewとして取得できます。Bitmapを生成して、Canvasで描画すれば、簡単にViewをBitmapに変換できます。
// View view;
Bitmap bitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas();
canvas.setBitmap(bitmap);
view.draw(canvas);
// (e.g.)
// ImageView imageView;
// imageView.setImageBitmap(bitmap);

2.ImageViewを最前面に表示する

最前面に表示するには、ImageViewをWindowManagerに追加します。
WindowManager.addView(View, WindowManager.LayoutParams)メソッドを使います。なお、いらなくなったらWindowManager.removeView(View)で削除できます。
WindowManager mWindowMgr = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
mWindowMgr.addView(imageView, layoutParams);
レイアウトパラメータを指定する必要があり、任意の位置に表示するのであれば次の値がいいと思います。
WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
layoutParams.gravity = Gravity.TOP | Gravity.LEFT;
layoutParams.x       = 0; // 表示位置 x
layoutParams.y       = 0; // 表示位置 y
layoutParams.width   = WindowManager.LayoutParams.WRAP_CONTENT;
layoutParams.height  = WindowManager.LayoutParams.WRAP_CONTENT;
layoutParams.flags   = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
layoutParams.format  = PixelFormat.TRANSLUCENT; // 透明を有効化

3.ImageViewの透明度指定

ドラッグ中のアイテムを見やすくするために、ImageViewを透過します。
ImageView.setAlpha(int)メソッドを使います。0〜255で透明度を指定します。値が大きいほど不透明になります。
//ImageView imageView;
imageView.setAlpha(128); // 透明度50% 

ただ、WindowManagerで透明度を有効にするには、必ず次を指定しておく必要があります。
// WindowManager.LayoutParams layoutParams;
layoutParams.format  = PixelFormat.TRANSLUCENT; // 透明を有効化

4.ImageViewを移動させるには

WindowManager.updateViewLayout(View, WindowManager.LayoutParams)メソッドでレイアウトを更新します。
WindowManager.addView(View, WindowManager.LayoutParams)メソッド時のWindowManager.LayoutParamsを保持しておき、x,y座標を変更して使いますと楽です。
// WindowManager mWindowMgr;
// WindowManager.LayoutParams layoutParams;
// ImageView imageView;
layoutParams.x       = 0; // 表示位置 x
layoutParams.y       = 0; // 表示位置 y
mWindowMgr.updateViewLayout(imageView, layoutParams);

こんな感じに、最前面でImageViewを自由に移動させらました。
ご参考にしてみてください。


2012年11月10日土曜日

[Android SDK] 埋め込みテキストファイルから文字列を取り出す

アプリ内に埋め込んだテキストファイルを文字列として取り出す方法を記載します。

ファイル構成

翻訳版も対応しているので、rawフォルダ名を変えて複数作成してください。
 +res
  +raw
   +update.txt (英語テキストファイル)
  +raw-ja
   +update.txt (日本語テキストファイル)

読み出しソース

ResourceクラスのopenRawResourceメソッドを使って読み出しをします。
// Context c;
String text = getRawTextFile(c, R.raw.update.txt);

private static String getRawTextFile(Context context, int resId) {
  InputStream st = null;
  byte[] buffer = null;
  try {
    st = context.getResources().openRawResource(resId);
      buffer = new byte[st.available()];
    while((st.read(buffer)) != -1) {}
  } catch (IOException e) {
  } finally{
    if (st != null) {
      try{
        st.close();
      }catch(IOException e2) {}
    }
  }
  if (buffer != null) {
    return new String(buffer);
  }
  return null;
}

こんな感じで、アプリの更新履歴をテキストファイルとしてアプリ内に埋め込んで使っています。

2012年11月9日金曜日

[Android SDK] ResourceからカラーフィルタしたBitmapを作成する

Resourceにある画像をカラーフィルタ処理をした、Bitmapを作成する方法を書きます。

ソース

// RemoteViews rv;
// int resId;
// Context context;
Bitmap icon = BitmapFactory.decodeResource(context.getResources(), resId);
Bitmap bitmap = Bitmap.createBitmap(icon.getWidth(), icon.getHeight(), icon.getConfig());
LightingColorFilter filter1 = new LightingColorFilter(0xFFFFFF, Color.WHITE);
Canvas canvas = new Canvas(bitmap);
Paint p = new Paint();
p.setColorFilter(filter1);
canvas.drawBitmap(icon, 0, 0, p);
// rv.setImageViewBitmap(R.id.icon, bitmap);

解説

ウィジェット作成していて、画像を貼り付けるにはResourceIDかBitmapしか方法がなくて、DrawableだったらsetColorFilterを使えば簡単にできたんだけど。仕方ないので、バッファBimapにカラーフィルタ処理付きで画像(Bitmap)を描画して作成しました。

結果

こんなアイコンをウィジェットに白色加工して貼り付けました。





色違いアイコンを作り直さなくていいから楽ちん。



2012年8月22日水曜日

[Android SDK] 全画面カスタムダイアログの作成

通常のダイアログは画面中央にちょこんと小窓が表示されますが、Activityのように全画面表示に変更することができます。

以下の手順で、ダイアログをカスタマイズします。
(ダイアログを継承して全画面表示にする際には、setContentViewでレイアウトを設定してから設定変更します)

1.ダイアログの大きさが全画面にする
//Dialog dialog;
dialog.getWindow().setLayout(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT);


2.ダイアログの境界線を非表示にする

//Dialog dialog;
dialog.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));


3.タイトルバーを非常にする
//Dialog dialog;
requestWindowFeature(Window.FEATURE_NO_TITLE);



以上で全画面表示されるはずです。



2012年3月4日日曜日

[Android SDK] 描画の基礎

Androidの描画の基礎として、Canvas、Paintクラスの使い方をまとめました。

2012年3月2日金曜日

[Android SDK] 加速度センサで傾きを測定する

Android携帯には様々なセンサが搭載されています。
機種によってまちまちですが、その中でも加速度センサを利用して、Android携帯の傾きを測定してみます。

まずは、SensorManagerという、センサ関連を統括して管理しているサービスを取得します。
SensorManager manager = (SensorManager)getSystemService(SENSOR_SERVICE);

続いて、センサの状態が変化したときに呼ばれるSensorEventListenerというリスナーを作成します。
サブクラスに実装するか、実装してインスタンスを作成してください。
SensorEventListener lis = new SensorEventListener() {
    // センサの精度が変化したときに呼ばれる
    public void onAccuracyChanged(Sensor sensor, int accuracy) {}
    // センサの値が変化したときに呼ばれる
    public void onSensorChanged(SensorEvent event) {}
};

試しに、Activityの中に加速度センサで取得した値を表示するサンプルを作成してみました。
/* フィールド変数 */
SensorManager mSensorManager;

/* 初期化処理メソッド */ {
 // センサーマネージャを取得
 mSensorManager = (SensorManager) c.getSystemService(Context.SENSOR_SERVICE);
 List sensors = mSensorManager.getSensorList(Sensor.TYPE_ACCELEROMETER);
 if (sensors != null && sensors.size() > 0) {
  Sensor s = sensors.get(0);
  mSensorManager.registerListener(mSensorListener, s, SensorManager.SENSOR_DELAY_UI);
 }
}
/* 終了処理メソッド */ {
 // センサーマネージャを破棄
 mSensorManager.unregisterListener(mSensorListener);
 mSensorManager = null;
}
SensorEventListener mSensorListener = new SensorEventListener() {
 public void onAccuracyChanged(Sensor sensor, int accuracy) {
  Log.d(TAG, sensor.getName()+":"+accuracy);
 }
 public void onSensorChanged(SensorEvent event) {
  if (event.values.length == 3) {
   Log.d(TAG, event.sensor.getName()+" ("+event.values[0]+","+event.values[1]+","+event.values[2]+")");
  }
 }
}

解説すると、まずは加速度センサのオブジェクトを取得するために、引数にSensor.TYPE_ACCELEROMETERを指定します。
List sensors = mSensorManager.getSensorList(Sensor.TYPE_ACCELEROMETER);

Android携帯によっては同一センサが複数搭載しているケースがあるため、Listオブジェクトが返り値となっている。
とりあえず、加速度センサが複数ついていないハズなので、要素0番目を取得してリスナーに登録する。
if (sensors != null && sensors.size() > 0) {
 Sensor s = sensors.get(0);
 mSensorManager.registerListener(mSensorListener, s, SensorManager.SENSOR_DELAY_UI);
}
ここでの3番目の引数は、センサー状態を通知する際の遅延時間です。
加速度センサの使用用途に合わせて、早すぎず遅すぎず適切なものを選ぶと良い。
定数の名前からも分かるように用途が分かりますね。
SensorManager.SENSOR_DELAY_FASTEST:0ms
SensorManager.SENSOR_DELAY_GAME:20ms
SensorManager.SENSOR_DELAY_UI:60ms
SensorManager.SENSOR_DELAY_NORMAL:200ms

肝心なSensorEventの中身ですが、重要なのはvaluesの値です。
加速度センサの場合はAndroid携帯を正面に持った状態で
values[0] : X軸 左右(左+、右-)
values[1] : Y軸 上下(下+、上-)
values[2] : Z軸 前後(後ろ側+、手前-)

という風な加速度センサの値が入っている。

常に重力分(9.8m/s'2=約10.0)が働いているため、静止状態でベクトルの大きさを計算すると10.0となる。
要するに、平らな机の置くと、後ろ側方向にのみ重力がかかるので、
・values[0]:0.0
・values[1]:0.0
・values[2]:10.0
となる。

試しにやってみるのが一番です。

最後にActivity破棄されるときにはリスナーも登録破棄してくださいね。
mSensorManager.unregisterListener(mSensorListener);






2012年3月1日木曜日

[Android SDK] SurfaceViewを使った高速描画

SurfaceViewは、描画用のスレッドがアプリケーションのスレッドと独立しているため、ゲームなど定期的な描画が要求される場合に向いている。
なお、SurfaceViewはAPI Level1から利用できる。

試しに、適当なサンプルを作成してみる。
1.Activityは最初に生成されるものから変更なし
package com.runpeta.android.angle;

import android.app.Activity;
import android.os.Bundle;

public class RpAngleActivity extends Activity {
 // アクティビティ作成時に最初に呼ばれる
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }
}

2.SurfaceViewのサブクラスを作り、線だけ描画する
package com.runpeta.android.angle;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

public class RpAngleSurfaceView extends SurfaceView implements SurfaceHolder.Callback {
 public RpAngleSurfaceView(Context context) {
  super(context);
  getHolder().addCallback(this);
 }
 public RpAngleSurfaceView(Context context, AttributeSet attrs) {
  super(context, attrs);
  getHolder().addCallback(this);
 }
 public RpAngleSurfaceView(Context context, AttributeSet attrs, int defStyle) {
  super(context, attrs, defStyle);
  getHolder().addCallback(this);
 }
 public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
  
 }
 public void surfaceCreated(SurfaceHolder holder) {
  doDraw();
 }
 public void surfaceDestroyed(SurfaceHolder holder) {
  
 }
 private void doDraw() {
     // キャンバスをロックする
     Canvas c = getHolder().lockCanvas();
     c.save();
     
     // ここにCanvasに描画処理を書く
     Paint p = new Paint();
     p.setColor(Color.BLACK);
     c.drawColor(Color.WHITE);
     c.drawLines(new float[]{20,20,60,60}, p);
     
     // キャンバスのロックを解除する
     c.restore();
     getHolder().unlockCanvasAndPost(c);
    }
}

3.メインレイアウトに作成したSurfaceViewを追加します。
・id:surface (とりあえず)
・width:fill_parent
・height:fill_parent

これで線なるものが描画されているハズだ。


これは非常に分かりづらいサンプルになってしまった。

ゲームのように定期的に再描画を行ってみる。

さきほどの"onDraw"をタイマーで定期的に呼び出すために、"ScheduledExecutorService"を利用します。
こんな感じにしようできますので、(定期処理内容)で"onDraw"を呼びます。
// タイマーを開始する
ScheduledExecutorService schedule;
schedule = Executors.newSingleThreadScheduledExecutor();
schedule.scheduleAtFixedRate(new Runnable(){
    public void run() {
        //定期処理内容

    }
}, 0, 100, TimeUnit.MILLISECONDS);

// タイマーを終了する
schedule.shutdown();

さきほどの線がアニメーションで伸び縮みするようにしてみます。
package com.runpeta.android.angle;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

public class RpAngleSurfaceView extends SurfaceView implements SurfaceHolder.Callback {
 private ScheduledExecutorService mSchedule;
 private Runnable repeatDraw = new Runnable() {
  public void run() {
   size += 5;
   if (size > 400) {
    size = 100;
   }
   doDraw();
  }
 };
 private int size = 100;
 public RpAngleSurfaceView(Context context) {
  super(context);
  getHolder().addCallback(this);
 }
 public RpAngleSurfaceView(Context context, AttributeSet attrs) {
  super(context, attrs);
  getHolder().addCallback(this);
 }
 public RpAngleSurfaceView(Context context, AttributeSet attrs, int defStyle) {
  super(context, attrs, defStyle);
  getHolder().addCallback(this);
 }
 public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
  
 }
 public void surfaceCreated(SurfaceHolder holder) {
  doDraw();
  mSchedule = Executors.newSingleThreadScheduledExecutor();
  mSchedule.scheduleAtFixedRate(repeatDraw, 0, 100, TimeUnit.MILLISECONDS);
 }
 public void surfaceDestroyed(SurfaceHolder holder) {
  mSchedule.shutdown();
  mSchedule = null;
 }
 private void doDraw() {
     // キャンバスをロックする
     Canvas c = getHolder().lockCanvas();
     c.save();
     
     // ここにCanvasに描画処理を書く
     Paint p = new Paint();
     p.setColor(Color.BLACK);
     c.drawColor(Color.WHITE);
     c.drawLines(new float[]{20,20,size,size}, p);
     
     // キャンバスのロックを解除する
     c.restore();
     getHolder().unlockCanvasAndPost(c);
    }
}

こんな感じで描画ができることが分かったので、後はCanvasとPaintの使い方次第でいろいろ描画できます。




2012年2月26日日曜日

[Android SDK] ステータスバーに通知する

ステータスバーを使いユーザに通知する機能があります。実物を見てもらった方が分かりやすいのです。
①ステータスバーに表示する
②ステータスバーに通知が蓄積される

これは、標準で用意されているNotificationManagerで簡単に、任意のメッセージやアイコンを持った通知を発行できます。
まずは、通知内容をNotificationに設定します。
// Context context;
// String message, item_title, item_message;
Notification n = new Notification();
n.icon = R.drawable.ic_launcher;// アイコン(drawable指定)ここではアプリのアイコン
n.tickerText = message;// ステータスバーに表示する文字列(CharSequence指定)
n.when = System.currentTimeMillis();
// 通知をタップしたときに発行するインテント
Intent i = new Intent(context, RpNotifyActivity.class);
n.setLatestEventInfo(context, item_title, item_message, PendingIntent.getActivity(context, 0, i, 0));
あとは、NotificationManagerに渡すとステータスバーに表示されます。
NotificationManager manager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
manager.notify(1,n);

2012年2月25日土曜日

[Android SDK] Android起動時にサービス等を起動する

Android起動時には"ACTION_REBOOT"インテントが発行されますので、BroadcastReceiverで受け取ることで任意の処理を実行できます。
1.BroadcastReceiverの準備
2.Intent Filterの登録
3.Permissionの登録

1.BroadcastReceiverの準備
参考に下記ように作成します。
package com.runpeta.android.notify;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;

public class RpNotifyReceiver extends BroadcastReceiver {
 private static final String TAG = "RpNotifyReceiver";

 @Override
 public void onReceive(Context context, Intent intent) {
  Log.d(TAG, "onReceive");
  String action = intent.getAction();
  if (action != null) {
   if (action.equals(Intent.ACTION_BOOT_COMPLETED)) {
    // システム起動完了時
    Log.d(TAG, "ACTION_BOOT_COMPLETED");
    context.startService(new Intent(context, RpNotifyService.class));
   }
  }
 }
}
2.Intent Filterの登録
AndroidManifest.xmlを開き、BroadcastReceiverのIntent Filterに"ACTION_REBOOT"を登録します。

3.Permissionの登録
AndroidManifest.xmlを開き、Permissionに"RECEIVE_BOOT_COMPLETED"を登録します。

以上で、Android起動時にBroadcastReceiverのonReceiveが呼ばれるようになります。

[Android SDK] 画面ON/OFFを検知する

画面の電源ON/OFF時にはインテントが発行されますので、BroadcastReceiverを利用して受け取るようにします。 まずは、受け取るためにBroadcastReceiverを作成します。作成したActivityもしくはService内に作成すると良い。
// ブロードキャストリスナー
BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
 @Override
 public void onReceive(Context context, Intent intent) {
  String action = intent.getAction();
  if (action != null) {
   if (action.equals(Intent.ACTION_SCREEN_ON)) {
    // 画面ON時
    Log.d(TAG, "SCREEN_ON");
   } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
    // 画面OFF時
    Log.d(TAG, "SCREEN_OFF");
   }
  }
 }
};
作成したBroadcastReceiverでインテントを受け取るには、IntentFilterを使い対象を登録する必要があります。 画面の電源ON/OFFでは次の二つを登録すると良い。
// リスナーの登録
Context c;
c.registerReceiver(broadcastReceiver, new IntentFilter(Intent.ACTION_SCREEN_ON));
c.registerReceiver(broadcastReceiver, new IntentFilter(Intent.ACTION_SCREEN_OFF));
また、受信するActivityまたはServiceのIntentFilterにも追加する。

なお、不要になったときは登録を削除します。
// リスナーの登録削除
Context c;
c.unregisterReceiver(broadcastReceiver);

[Android SDK] 電話の着信を監視する

TelephonyManagerを利用すると、電話の着信/通話中/待機時を検知することができる。
まずはシステムサービスからTelephonyManagerを取得し、listenでリスナーを登録する。
※Permissonに"android.permission.READ_PHONE_STATE"の登録が必要。
// 電話状態監視リスナー
PhoneStateListener mListener = new PhoneStateListener() { 
 public void onCallStateChanged(int state, String number) {
  switch(state) {
  case TelephonyManager.CALL_STATE_RINGING:// 着信時
   Log.d(TAG, "PhoneState: CALL_STATE_RINGING");
   break;
  case TelephonyManager.CALL_STATE_OFFHOOK:// 通話時
   Log.d(TAG, "PhoneState: CALL_STATE_OFFHOOK");
   break;
  case TelephonyManager.CALL_STATE_IDLE:// 待機時(リスナー登録時も呼ばれるようだ)
   Log.d(TAG, "PhoneState: CALL_STATE_IDLE");
   break;
  }
 }
};
TelephonyManager m = (TelephonyManager) this.getSystemService(Context.TELEPHONY_SERVICE);
m.listen(mListener, PhoneStateListener.LISTEN_CALL_STATE);
不在着信の検知は、前回の電話状態を記録することで可能です。
・通話終了=CALL_STATE_RINGING -> CALL_STATE_OFFHOOK -> CALL_STATE_IDLE
・不在着信=CALL_STATE_RINGING -> CALL_STATE_IDLE

2012年1月28日土曜日

Androidアプリ開発の参考記事まとめ



今話題のスマートホン、Androidの方ですがアプリの開発を始めてみました。iPhoneのアプリと違って、公開以外は無料でできるのが初心者にやさしい。あと、Webサイトに開発に役立つ記事がたくさん有志によって公開されているところも助かります。

簡単なアプリから開発を始めてみます。その中で、逆引き的に役だった記事をまとめていきます。