Android最速の
フォトグラファーに
俺はなる!!
@kassy_kz
for yapf 2014 / 5 / 3
最速になりたい
自己紹介
• 名前:@kassy_kz (かっしー)
• 二つ名:神奈川の健全王(自称)

    多摩川の直線鬼(自称)
• 趣味:カメラ

   (フォトマスター1級所持)
フォトグラファーにとって
最も重要なファクターとは
それはスピード
※個人の意見です
一瞬のシャッターチャンスを逃さない
それこそが真のフォトグラファー
※あくまで個人の意見です
つまり必要なのは
スピード!
Androidで

カメラの起動速度を極める
最速のフォトグラファーを目指して
通常の、カメラ起動までの流れ
2∼5ステップ
これでは

チャンスを逃してしまう…
端末の状態に関わらず
ワンステップでアプリを起動する
目標
Google Nowの起動シーケンスに着目
端末がどんな状態であろうと
「ホームボタン上スライド」
の1アクションで
Google Nowが起動する
ヨコが余ってんじゃね?
このサークルのヨコに
アイテムを追加できれば
「ホームボタン横スライド」
のワンアクションで
アプリを起動できるのでは!?
よろしい
!
ならば(ROMの)改造だ
着目するのは PhoneStatusBar
この部分は
PhoneStatusBarというところで

実装されている
パスは/frameworks/base/packages/SystemUI/src/com/android/systemui/...
PhoneStatusBarのコードを読む
	
  	
  	
  	
  private	
  void	
  prepareNavigationBarView()	
  {	
  
	
   	
   (中略)	
  
	
  	
  	
...
PhoneStatusBarのコードを読む
	
  	
  	
  	
  @Override	
  
	
  	
  	
  	
  public	
  void	
  showSearchPanel()	
  {	
  
	
  	
  	...
Homeキー押下で出現するこのViewは
SearchPanelViewと言うらしい
更にSearchPanelViewのコードを読む
	
  	
  	
  	
  @Override	
  
	
  	
  	
  	
  protected	
  void	
  onFinishInflate()	
  {	
  
	
 ...
さらに読む(そろそろ疲れてきた)
      prvandroid:targetDrawables="@array/navbar_search_targets”"
	
  	
  	
  	
  <array	
  name="navbar_s...
drawableを埋めてみた
	
  	
  	
  	
  <array	
  name="navbar_search_targets">	
  
	
  	
  	
  	
  	
  	
  	
  	
  <item>@*android...
追加画像がよしなに配置される!
明らかにヨコへの配置を前提にしたコードだった
将来のバージョンアップによってはもしかしたら…
アクションの取得はどうやってるのか
	
  	
  	
  	
  class	
  GlowPadTriggerListener	
  implements	
  GlowPadView.OnTriggerListener	
  {	
  
...
SearchPanelView
GlowPadView
アクションの取得はどうやってるのか
リスナー登録
コールバック

(引数はdrawableID)
SearchPanelView
GlowPadView
カメラ起動コードを埋め込む
	
  	
  	
  	
  class	
  GlowPadTriggerListener	
  implements	
  GlowPadView.OnTriggerListener	
  {	
  
	
  ...
デモ
神奈川の健全王が
シャッターチャンスに遭遇してから
シャッター押下までのタイムは
わずか0.8秒 (自分調べ) にすぎない
では、
その撮影プロセスを
もう一度見てみよう
カメラ起動まで常にワンアクション!
これで決まりだ!
上司ゴースト
大体最初から
ユースケースの整理が
配慮がたらんわ
バカもんが
端末がスリープ状態のときは

どうするんだ?
あ?
orz
端末スリープ状態から
ワンアクションでカメラを起動する
次の目標
イヤホンのボタンに着目
コレ
端末がスリープ状態でも
ボタンを押せば音楽の再生停止ができる
これを使えば
スリープ状態からでも
なんらかのアクションを起こせるのでは
問題はどうやって

マイクボタン押下を検出するかだ
ボタン押した時のログを見てみる
04-13 12:51:14.386: W/ContextImpl(28640): Implicit intents with startService are not safe: Intent { act=co...
ボタン押した時のログを見てみる
04-13 12:51:14.386: W/ContextImpl(28640): Implicit intents with startService are not safe: Intent { act=co...
Androidソースコードから検索
MediaFocusControl#registerMediaButtonIntent
AudioManager#registerMediaButtonEventReceiver
↑
この辺りが怪しい
調べたらフツーにリファレンスが出てきた…
http://developer.android.com/training/managing-audio/volume-playback.html
イヤホンボタンイベントを取得するコード
	
  	
  	
  	
  @Override	
  
	
  	
  	
  	
  public	
  int	
  onStartCommand(Intent	
  intent,	
  int...
さらに仕込む
<uses-permission android:name="android.permission.WAKE_LOCK"/>	
<uses-permission android:name="android.permission.D...
デモ
※本日二回目
多摩川の直線鬼が
シャッターチャンスに遭遇してから
シャッター押下までのタイムは
わずか1.2秒 (自分調べ) にすぎない
では、
その撮影プロセスを
もう一度見てみよう
最速!
あらゆる状況で最速!!
友人 なんか似たようなん
既に見たで
僕
僕
僕
友人
絶望が俺のゴールだ
発表は以上です
ご静聴ありがとうございました
申し訳ありませんでした
Android最速のフォトグラファーに、俺はなる!
Android最速のフォトグラファーに、俺はなる!
Upcoming SlideShare
Loading in …5
×

Android最速のフォトグラファーに、俺はなる!

3,410 views

Published on

2014/5/3 横浜PF部で発表したスライドです。
カメラの起動高速化について真面目に考えてみた様子を記しています。

Published in: Technology
0 Comments
10 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
3,410
On SlideShare
0
From Embeds
0
Number of Embeds
167
Actions
Shares
0
Downloads
4
Comments
0
Likes
10
Embeds 0
No embeds

No notes for slide

Android最速のフォトグラファーに、俺はなる!

  1. 1. Android最速の フォトグラファーに 俺はなる!! @kassy_kz for yapf 2014 / 5 / 3
  2. 2. 最速になりたい
  3. 3. 自己紹介 • 名前:@kassy_kz (かっしー) • 二つ名:神奈川の健全王(自称)
     多摩川の直線鬼(自称) • 趣味:カメラ
    (フォトマスター1級所持)
  4. 4. フォトグラファーにとって 最も重要なファクターとは
  5. 5. それはスピード ※個人の意見です
  6. 6. 一瞬のシャッターチャンスを逃さない それこそが真のフォトグラファー ※あくまで個人の意見です
  7. 7. つまり必要なのは スピード!
  8. 8. Androidで
 カメラの起動速度を極める 最速のフォトグラファーを目指して
  9. 9. 通常の、カメラ起動までの流れ 2∼5ステップ
  10. 10. これでは
 チャンスを逃してしまう…
  11. 11. 端末の状態に関わらず ワンステップでアプリを起動する 目標
  12. 12. Google Nowの起動シーケンスに着目 端末がどんな状態であろうと 「ホームボタン上スライド」 の1アクションで Google Nowが起動する
  13. 13. ヨコが余ってんじゃね? このサークルのヨコに アイテムを追加できれば 「ホームボタン横スライド」 のワンアクションで アプリを起動できるのでは!?
  14. 14. よろしい ! ならば(ROMの)改造だ
  15. 15. 着目するのは PhoneStatusBar この部分は PhoneStatusBarというところで
 実装されている パスは/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/
  16. 16. PhoneStatusBarのコードを読む        private  void  prepareNavigationBarView()  {       (中略)                mNavigationBarView.getHomeButton().setOnTouchListener(mHomeSearchActionListener);                updateSearchPanel();          }   PhoneStatusBar.java ↑ Homeボタンをおした時のリスナーを登録してる箇所を発見!        View.OnTouchListener  mHomeSearchActionListener  =  new  View.OnTouchListener()  {                  public  boolean  onTouch(View  v,  MotionEvent  event)  {              (中略)                          mHandler.postDelayed(mShowSearchPanel,  mShowSearchHoldoff);               (中略)        };   PhoneStatusBar.java ↑ リスナーの実装はこれ、mShowSearchPanelメソッドを呼び出している!
  17. 17. PhoneStatusBarのコードを読む        @Override          public  void  showSearchPanel()  {                  int  msg  =  MSG_OPEN_SEARCH_PANEL;                  mHandler.removeMessages(msg);                  mHandler.sendEmptyMessage(msg);          }   BaseStatusBar.java (PhoneStatusBarの基底クラス) ↑ handlerにメッセ投げている        protected  class  H  extends  Handler  {                  public  void  handleMessage(Message  m)  {                          switch  (m.what)  {                            case  MSG_OPEN_SEARCH_PANEL:                                    if  (DEBUG)  Log.d(TAG,  "opening  search  panel");                                    if  (mSearchPanelView  !=  null  &&  mSearchPanelView.isAssistantAvailable())  {                                            mSearchPanelView.show(true,  true);                                            onShowSearchPanel();                                    }                                    break;                          }                  }          }   ↑ handlerの受け側。SearchPanelViewのshow() メソッドをコールしている
  18. 18. Homeキー押下で出現するこのViewは SearchPanelViewと言うらしい
  19. 19. 更にSearchPanelViewのコードを読む        @Override          protected  void  onFinishInflate()  {                    (中略)                  mGlowPadView  =  (GlowPadView)  findViewById(R.id.glow_pad_view);                  mGlowPadView.setOnTriggerListener(mGlowPadViewListener);          }   SearchPanelView.java ↑ 入れ子にGlowPadViewというViewが貼られている事がわかる。    public  GlowPadView(Context  context,  AttributeSet  attrs)  {                  (中略)                  if  (a.getValue(R.styleable.GlowPadView_targetDrawables,  outValue))  {                          internalSetTargetResources(outValue.resourceId);                  }   GlowPadView.java ↑ 独自カスタムViewの書き方をしている。 XMLファイルの「targetDrawables」というところから値を取ってきている事がわかる internalSetTargetResources以下では、drawbleの配置を行っている。
  20. 20. さらに読む(そろそろ疲れてきた)       prvandroid:targetDrawables="@array/navbar_search_targets”"        <array  name="navbar_search_targets">                  <item>@null</item>                  <item>@*android:drawable/ic_action_assist_generic</item>                  <item>@null</item>                  <item>@null</item>          </array> /frameworks/base/packages/SystemUI/res/layout/status_bar_search_panel.xml ↑ array/navbar_search_targetsというところを参照している /frameworks/base/packages/SystemUI/res/values-land/arrays.xml ↑ drawable4つを格納する配列、   そして1つを除いてnullが格納されているという の状態
  21. 21. drawableを埋めてみた        <array  name="navbar_search_targets">                  <item>@*android:drawable/ic_lockscreen_camera_activated</item>                  <item>@*android:drawable/ic_action_assist_generic</item>                  <item>@*android:drawable/ic_lockscreen_camera_activated</item>                  <item>@*android:drawable/ic_lockscreen_camera_activated</item>          </array> /frameworks/base/packages/SystemUI/res/values-land/arrays.xml ↑nullの箇所に自分で持ってきたdrawableのIDを埋め込んでみた 画像は以下の場所に良さげなのがあったので流用 /frameworks/base/packages/Keyguard/res/ drawable-xhdpi/ic_lockscreen_camera_activated.png
  22. 22. 追加画像がよしなに配置される! 明らかにヨコへの配置を前提にしたコードだった 将来のバージョンアップによってはもしかしたら…
  23. 23. アクションの取得はどうやってるのか        class  GlowPadTriggerListener  implements  GlowPadView.OnTriggerListener  {                      public  void  onTrigger(View  v,  final  int  target)  {                          final  int  resId  =  mGlowPadView.getResourceIdForTarget(target);                              switch  (resId)  {                                  case  com.android.internal.R.drawable.ic_action_assist_generic:                                          mWaitingForLaunch  =  true;                                          startAssistActivity();                                          vibrate();                                          break;                          }                  }   SearchPanelView.java
  24. 24. SearchPanelView GlowPadView アクションの取得はどうやってるのか リスナー登録 コールバック
 (引数はdrawableID) SearchPanelView GlowPadView
  25. 25. カメラ起動コードを埋め込む        class  GlowPadTriggerListener  implements  GlowPadView.OnTriggerListener  {                      public  void  onTrigger(View  v,  final  int  target)  {                          final  int  resId  =  mGlowPadView.getResourceIdForTarget(target);                              switch  (resId)  {                                  case  com.android.internal.R.drawable.ic_action_assist_generic:                                          mWaitingForLaunch  =  true;                                          startAssistActivity();                                          vibrate();                                          break;                                      case  17302260:                                          final  Intent  intent  =  new  Intent();                                          postDelayed(new  Runnable()  {                                                  public  void  run()  {                                                          intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);                                                          intent.setAction("android.media.action.IMAGE_CAPTURE");                                                          mContext.startActivityAsUser(intent,                                                                        new  UserHandle(UserHandle.USER_CURRENT));                                                  }                                          },  SEARCH_PANEL_HOLD_DURATION);                                          break;                          }                  }   SearchPanelView.java 追加 ←自分で追加したdrawableのID
  26. 26. デモ
  27. 27. 神奈川の健全王が シャッターチャンスに遭遇してから シャッター押下までのタイムは わずか0.8秒 (自分調べ) にすぎない
  28. 28. では、 その撮影プロセスを もう一度見てみよう
  29. 29. カメラ起動まで常にワンアクション!
  30. 30. これで決まりだ!
  31. 31. 上司ゴースト 大体最初から ユースケースの整理が 配慮がたらんわ バカもんが 端末がスリープ状態のときは
 どうするんだ? あ?
  32. 32. orz
  33. 33. 端末スリープ状態から ワンアクションでカメラを起動する 次の目標
  34. 34. イヤホンのボタンに着目 コレ 端末がスリープ状態でも ボタンを押せば音楽の再生停止ができる
  35. 35. これを使えば スリープ状態からでも なんらかのアクションを起こせるのでは 問題はどうやって
 マイクボタン押下を検出するかだ
  36. 36. ボタン押した時のログを見てみる 04-13 12:51:14.386: W/ContextImpl(28640): Implicit intents with startService are not safe: Intent { act=com.google.android.music.NETWORK_MONITOR_SERVICE } android.content.ContextWrapper.bindService:517 com.google.android.music.utils.SafeServiceConnection$ServiceConnectionImp.bindService:98 com.google.android.music.utils.SafeServiceConnection.bindService:259 04-13 12:51:14.406: D/SystemUtils(28640): getSystemProperty: lpa.decode=null 04-13 12:51:14.406: I/MediaFocusControl(771): Remote Control registerMediaButtonIntent() for PendingIntent{4313edb0: PendingIntentRecord{431d35c8 com.google.android.music broadcastIntent}} 04-13 12:51:14.416: V/Avrcp(2343): New genId = 6, clearing = 1 04-13 12:51:14.416: V/Avrcp(2343): New genId = 7, clearing = 1 04-13 12:51:14.416: I/LocalDevicePlayback(28640): play: currentPos=-1 04-13 12:51:14.416: I/MediaFocusControl(771): AudioFocus requestAudioFocus() from android.media.AudioManager@426b6090com.google.android.music.playback.LocalDevicePlayback$9@42736830 04-13 12:51:14.416: V/Avrcp(2343): New genId = 8, clearing = 0 04-13 12:51:14.416: D/CacheService(28640): onCreate 04-13 12:51:14.416: D/CacheService(28640): onBind 04-13 12:51:14.426: W/ContextImpl(28640): Implicit intents with startService are not safe: Intent { act=com.google.android.music.NETWORK_MONITOR_SERVICE } android.content.ContextWrapper.bindService:517 com.google.android.music.utils.SafeServiceConnection$ServiceConnectionImp.bindService:98 com.google.android.music.utils.SafeServiceConnection.bindService:259 04-13 12:51:14.426: I/LocalDevicePlayback(28640): Streaming client created. 04-13 12:51:14.456: I/LocalDevicePlayback(28640): stop: willPlay=false, currentPos=20 04-13 12:51:14.466: V/Avrcp(2343): updatePlayPauseState, old=0, state=0 04-13 12:51:14.466: V/Avrcp(2343): position=0 04-13 12:51:14.466: V/Avrcp(2343): mMetadata=Metadata[artist=null trackTitle=null albumTitle=null] 04-13 12:51:14.466: V/Avrcp(2343): duration=0 04-13 12:51:14.466: V/Avrcp(2343): updatePlayPauseState, old=0, state=3 04-13 12:51:14.466: V/Avrcp(2343): position=0 04-13 12:51:14.476: I/LocalDevicePlayback(28640): open: id=[19, DEFAULT], pos=0, playPos=20, fromUser=true, track=to the beginning 04-13 12:51:14.486: D/dalvikvm(28640): GC_CONCURRENT freed 322K, 2% free 17459K/17812K, paused 2ms+1ms, total 12ms 04-13 12:51:14.486: D/LocalAsyncMediaPlayer(28640): Event logging MUSIC_START_PLAYBACK_REQUESTED: 19/: local playback 04-13 12:51:14.536: D/dalvikvm(28640): GC_FOR_ALLOC freed 33K, 2% free 17605K/17960K, paused 13ms, total 13ms 04-13 12:51:14.546: D/dalvikvm(28640): GC_FOR_ALLOC freed 2K, 2% free 17749K/18108K, paused 12ms, total 13ms 04-13 12:51:14.566: D/dalvikvm(28640): GC_FOR_ALLOC freed 471K, 5% free 17456K/18256K, paused 12ms, total 12ms 04-13 12:51:14.586: D/dalvikvm(28640): GC_CONCURRENT freed 3K, 3% free 17878K/18256K, paused 2ms+1ms, total 15ms 04-13 12:51:14.606: D/dalvikvm(28640): GC_FOR_ALLOC freed 9K, 3% free 17879K/18256K, paused 9ms, total 9ms 04-13 12:51:14.606: I/dalvikvm-heap(28640): Grow heap (frag case) to 17.768MB for 294928-byte allocation 04-13 12:51:14.616: D/dalvikvm(28640): GC_FOR_ALLOC freed <1K, 3% free 18167K/18548K, paused 10ms, total 10ms 04-13 12:51:14.616: V/Avrcp(2343): updatePlayPauseState, old=3, state=3 04-13 12:51:14.616: V/Avrcp(2343): position=170455 04-13 12:51:14.626: I/ActivityManager(771): Start proc com.android.musicfx for broadcast com.android.musicfx/.ControlPanelReceiver: pid=8691 uid=10013 gids={50013, 3003, 3002} 04-13 12:51:14.636: I/AudioFlinger(183): HAL output buffer size 32768 frames, normal mix buffer size 32768 frames 04-13 12:51:14.636: I/AudioFlinger(183): AudioFlinger's thread 0xb7fc0ce8 ready to run 04-13 12:51:14.636: D/dalvikvm(181): GC_EXPLICIT freed 42K, 1% free 16750K/16824K, paused 1ms+2ms, total 15ms 04-13 12:51:14.636: W/AudioFlinger(183): moveEffectChain_l() effect chain for session 0 not on source thread 0xb5ba1008 とりあえず
  37. 37. ボタン押した時のログを見てみる 04-13 12:51:14.386: W/ContextImpl(28640): Implicit intents with startService are not safe: Intent { act=com.google.android.music.NETWORK_MONITOR_SERVICE } android.content.ContextWrapper.bindService:517 com.google.android.music.utils.SafeServiceConnection$ServiceConnectionImp.bindService:98 com.google.android.music.utils.SafeServiceConnection.bindService:259 04-13 12:51:14.406: D/SystemUtils(28640): getSystemProperty: lpa.decode=null 04-13 12:51:14.406: I/MediaFocusControl(771): Remote Control registerMediaButtonIntent() for PendingIntent{4313edb0: PendingIntentRecord{431d35c8 com.google.android.music broadcastIntent}} 04-13 12:51:14.416: V/Avrcp(2343): New genId = 6, clearing = 1 04-13 12:51:14.416: V/Avrcp(2343): New genId = 7, clearing = 1 04-13 12:51:14.416: I/LocalDevicePlayback(28640): play: currentPos=-1 04-13 12:51:14.416: I/MediaFocusControl(771): AudioFocus requestAudioFocus() from android.media.AudioManager@426b6090com.google.android.music.playback.LocalDevicePlayback$9@42736830 04-13 12:51:14.416: V/Avrcp(2343): New genId = 8, clearing = 0 04-13 12:51:14.416: D/CacheService(28640): onCreate 04-13 12:51:14.416: D/CacheService(28640): onBind 04-13 12:51:14.426: W/ContextImpl(28640): Implicit intents with startService are not safe: Intent { act=com.google.android.music.NETWORK_MONITOR_SERVICE } android.content.ContextWrapper.bindService:517 com.google.android.music.utils.SafeServiceConnection$ServiceConnectionImp.bindService:98 com.google.android.music.utils.SafeServiceConnection.bindService:259 04-13 12:51:14.426: I/LocalDevicePlayback(28640): Streaming client created. 04-13 12:51:14.456: I/LocalDevicePlayback(28640): stop: willPlay=false, currentPos=20 04-13 12:51:14.466: V/Avrcp(2343): updatePlayPauseState, old=0, state=0 04-13 12:51:14.466: V/Avrcp(2343): position=0 04-13 12:51:14.466: V/Avrcp(2343): mMetadata=Metadata[artist=null trackTitle=null albumTitle=null] 04-13 12:51:14.466: V/Avrcp(2343): duration=0 04-13 12:51:14.466: V/Avrcp(2343): updatePlayPauseState, old=0, state=3 04-13 12:51:14.466: V/Avrcp(2343): position=0 04-13 12:51:14.476: I/LocalDevicePlayback(28640): open: id=[19, DEFAULT], pos=0, playPos=20, fromUser=true, track=to the beginning 04-13 12:51:14.486: D/dalvikvm(28640): GC_CONCURRENT freed 322K, 2% free 17459K/17812K, paused 2ms+1ms, total 12ms 04-13 12:51:14.486: D/LocalAsyncMediaPlayer(28640): Event logging MUSIC_START_PLAYBACK_REQUESTED: 19/: local playback 04-13 12:51:14.536: D/dalvikvm(28640): GC_FOR_ALLOC freed 33K, 2% free 17605K/17960K, paused 13ms, total 13ms 04-13 12:51:14.546: D/dalvikvm(28640): GC_FOR_ALLOC freed 2K, 2% free 17749K/18108K, paused 12ms, total 13ms 04-13 12:51:14.566: D/dalvikvm(28640): GC_FOR_ALLOC freed 471K, 5% free 17456K/18256K, paused 12ms, total 12ms 04-13 12:51:14.586: D/dalvikvm(28640): GC_CONCURRENT freed 3K, 3% free 17878K/18256K, paused 2ms+1ms, total 15ms 04-13 12:51:14.606: D/dalvikvm(28640): GC_FOR_ALLOC freed 9K, 3% free 17879K/18256K, paused 9ms, total 9ms 04-13 12:51:14.606: I/dalvikvm-heap(28640): Grow heap (frag case) to 17.768MB for 294928-byte allocation 04-13 12:51:14.616: D/dalvikvm(28640): GC_FOR_ALLOC freed <1K, 3% free 18167K/18548K, paused 10ms, total 10ms 04-13 12:51:14.616: V/Avrcp(2343): updatePlayPauseState, old=3, state=3 04-13 12:51:14.616: V/Avrcp(2343): position=170455 04-13 12:51:14.626: I/ActivityManager(771): Start proc com.android.musicfx for broadcast com.android.musicfx/.ControlPanelReceiver: pid=8691 uid=10013 gids={50013, 3003, 3002} 04-13 12:51:14.636: I/AudioFlinger(183): HAL output buffer size 32768 frames, normal mix buffer size 32768 frames 04-13 12:51:14.636: I/AudioFlinger(183): AudioFlinger's thread 0xb7fc0ce8 ready to run 04-13 12:51:14.636: D/dalvikvm(181): GC_EXPLICIT freed 42K, 1% free 16750K/16824K, paused 1ms+2ms, total 15ms 04-13 12:51:14.636: W/AudioFlinger(183): moveEffectChain_l() effect chain for session 0 not on source thread 0xb5ba1008 アヤシイ I/MediaFocusControl(771): Remote Control registerMediaButtonIntent() for PendingIntent{4313edb0: PendingIntentRecord{431d35c8 とりあえず
  38. 38. Androidソースコードから検索 MediaFocusControl#registerMediaButtonIntent AudioManager#registerMediaButtonEventReceiver ↑ この辺りが怪しい
  39. 39. 調べたらフツーにリファレンスが出てきた… http://developer.android.com/training/managing-audio/volume-playback.html
  40. 40. イヤホンボタンイベントを取得するコード        @Override          public  int  onStartCommand(Intent  intent,  int  flags,  int  startId){                  AudioManager  am  =  (AudioManager)  this.getSystemService(Context.AUDIO_SERVICE);                  myEventReceiver  =  new  ComponentName(getPackageName(),  MyRemoteControlEventReceiver.class.getName());                  am.registerMediaButtonEventReceiver(myEventReceiver);                  return  START_NOT_STICKY;          }                  @Override          public  void  onDestroy()  {                  AudioManager  am  =  (AudioManager)  this.getSystemService(Context.AUDIO_SERVICE);                  am.unregisterMediaButtonEventReceiver(myEventReceiver);          }   MainService.java @Override public void onReceive(Context context, Intent intent) { // カメラ起動 Intent intent2 = new Intent(); //intent2.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent2.setAction("android.media.action.IMAGE_CAPTURE"); startActivity(intent2); } MyRemoteControlEventReceiver.java
  41. 41. さらに仕込む <uses-permission android:name="android.permission.WAKE_LOCK"/> <uses-permission android:name="android.permission.DISABLE_KEYGUARD"/> AndroidManifest.xml PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE); PowerManager.WakeLock wakelock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.ON_AFTER_RELEASE, "Your App Tag"); wakelock.acquire(); wakelock.release(); // フラグセット Window window = getWindow(); window.addFlags( WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED); スリープを解除するコード 画面ロックをパスするコード ここまでROM改造なし、誰でもボタン入力を扱える
  42. 42. デモ ※本日二回目
  43. 43. 多摩川の直線鬼が シャッターチャンスに遭遇してから シャッター押下までのタイムは わずか1.2秒 (自分調べ) にすぎない
  44. 44. では、 その撮影プロセスを もう一度見てみよう
  45. 45. 最速! あらゆる状況で最速!!
  46. 46. 友人 なんか似たようなん 既に見たで 僕
  47. 47.
  48. 48. 僕 友人
  49. 49. 絶望が俺のゴールだ
  50. 50. 発表は以上です ご静聴ありがとうございました 申し訳ありませんでした

×