Android OSから発行されるブロードキャストインテントの受信

Androidではいくつかの標準ブロードキャストインテントが定義されていて、システムの様々な状態変化を取得できるようになっています。今回はアプリのアンインストールの検知を試してみました。
# 最初、機内モードIN/OUTを検知しようとしてうまく検知できず…

【参考】 android.content.Intent のリファレンスの Standard Broadcast Actions の項
http://developer.android.com/reference/android/content/Intent.html

テスト環境は以下の通りです。

AndroidManifest.xmlの記述

の子要素として を記述します。PACKAGE_REMOVED (アプリのアンインストール時に発行されるブロードキャストインテント) を受信して、android:name属性に指定したUninstallReceiverクラスを起動することを指定います。
試してみた限りでは、intent-filter中の は必須で、これがないとロードキャストレシーバが起動されませんでした。

    <application>
    ....
        <receiver android:name=".UninstallReceiver">
            <intent-filter>
                <action android:name="android.intent.action.PACKAGE_REMOVED" />  
                <data android:scheme="package" />       
            </intent-filter>
        </receiver>
    </application>

Broadcast Receiverの作成

以下のようなブロードキャストレシーバを記述します。AndroidManifestの記述に従って、PACKAGE_REMOVEDが発行されるとUninstallReceiverがインスタンス化され、onReceiverが呼び出されることになります。ここでは、別のアクティビティ (Main) を起動する処理を行っています。

UninstallReceiver.java

public class UninstallReceiver extends BroadcastReceiver {
    private static final String TAG = "DEBUG";
        @Override
        public void onReceive(Context context, Intent received_intent) {
            Log.d(TAG, "receiver activated");
            Intent intent = new Intent(context, Main.class);
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            intent.setAction(Intent.ACTION_MAIN);
            context.startActivity(intent);
	}
    }
}

実行結果

上記のテスト用アプリをインストールした後で、別のダミーアプリのインストール→アンインストールを行ったところ、UninstallReceiverで呼び出しているアクティビティが表示されることを確認しました。
また、logcatを見ると、以下のようにUninstallReceiver#onReceive中で出力しているログの存在を確認できます。

(メモ) Ubuntu 12.04 on Zenbook Prime UX31A

最近Zenbook Prime UX31Aを購入したので、Ubuntuを入れた際の設定などのメモを書いておきます。

機種・バージョン情報

  • ZENBOOK Prime UX31A-R4256 (Intel Core i7-3517U, 1.9GHz×2コア, メモリ 4GB, SSD 256GB)
  • Ubuntu Desktop 12.04 LTS 64bit

最初Linux Mint 13 Cinnamonを試したものの、GRUBのインストールに失敗したので、ひとまず何も考えずにUbuntuに切り替えました。

Ubuntuのインストール

UX31Aは従来のBIOSに代わるUEFIを用いてブートするので、パーティションの扱いが以前とは異なっています (今どきのマシンはみんなこうなんでしょうかね…?)

初期状態でWindowsのデータ領域 (Dドライブ) として確保されていた約130GBのパーティションを3つに分け、以下のように割り当てました。

(GUIDパーティションテーブルのため、従来の基本パーティションや論理パーティションの概念はない)

Ubuntu上のGNU partedでは以下のように見えています。

(parted) print list                                                       
Model: ATA SanDisk SSD U100 (scsi)
Disk /dev/sda: 252GB
Sector size (logical/physical): 512B/512B
Partition Table: gpt

Number  Start   End    Size    File system  Name                          Flags
 1      1049kB  211MB  210MB   fat32        EFI system partition          boot
 2      211MB   345MB  134MB                Microsoft reserved partition  msftres
 3      345MB   104GB  104GB   ntfs         Basic data partition
 4      104GB   109GB  4295MB               Basic data partition
 5      109GB   129GB  20.0GB  ext4
 7      129GB   149GB  20.0GB
 8      149GB   241GB  92.6GB  ext4
 6      241GB   252GB  10.7GB  ntfs         Basic data partition          hidden, diag

タッチパッド操作について

Ubuntuインストール直後の状態で、2本指スクロール含めてタッチパッド使えていますが、右クリックが機能しません。
2本指タップ (クリックではなくタッチパッドに短く触れる操作) が右クリックとして機能します。

OSが固まる現象とカーネル更新

インストール直後の状態では、ブラウザ (Firefox, Chrome) でWebサイトにアクセスするタイミングでかなり頻繁にOS全体がフリーズする現象が発生していました。

Ubuntuのcomminuty wikiページを見ると、2012/7/22時点で最新の3.2.0-26バージョンのカーネルWi-Fi接続時にkernel panicが発生する問題があるようです。
https://help.ubuntu.com/community/AsmusZenbookPrime#Bugs_and_issues

この状況に該当するかどうかは明確ではないものの、proposed (テスト版) の3.2.0-27では問題が解決されているとのことなので、ひとまずこれに置き換えます。

初期状態ではproposedはapt-getの取得対象に入っていないので、Ubuntuソフトウェアセンターの「ソフトウェアソース」で、「プレリリースされたアップデート (precise-proposed) にチェックを入れる必要があります。

この状態でapt-getやアップデートマネージャ等によりlinux-image-3.2.0-27-genericを入れることができます。

カーネルを置き換えた状態で2日ほど使って限りではフリーズは発生していないので、当面これで問題なさそうです。

Unsettingsを用いたグローバルメニュー無効化

Zenbookに限った話ではありませんが、最近のUbuntuではアプリケーションのファイル、編集などのメニューが画面全体の最上部に出る (グローバルメニューと呼ぶらしい) のがどうも使いづらいので、Unsettingsという設定ツールを使って、ウィンドウ上部に来るように変更します。

初期状態でのUbuntuデスクトップ (グローバルメニュー表示)

参考情報:

UnsettingsはUbuntu公式のリポジトリには含まれないので、aptにリポジトリを追加した後でapt-getでインストールします。

$ sudo add-apt-repository ppa:diesch/testing
$ sudo apt-get update
$ sudo apt-get install unsettings

Unsettingsを起動して、Windowsタブの中の「Global menu」をOFFにします (有効にするには一旦ログアウトする必要あり)。

グローバルメニューをOFFにした状態でのウィンドウの例

(未解決) Windows 7とのデュアルブート

現在、GRUBのブートメニューにはWindows 7のエントリは現れるものの、それを選択すると

error: invalid EFI file path.

と出てブートできない状況です。これについては今のところ未解決です。

ブラウザから送出されるWebSocketハンドシェイクを取得

WebSocketプロトコルRubyTCPServerのお勉強を兼ねて、WebブラウザからWebSocketサーバへの接続時に、ブラウザが送出するハンドシェイクの内容を取得してみます。

参考情報:

動作環境:

TCPサーバ

RubyリファレンスマニュアルのTCPServerクラス中のサンプルほぼそのままです。
WebSocketのハンドシェイク中のヘッダフィールドをテキトーに解釈しています。

ws_handshake.rb:

require 'socket'

server = TCPServer.new(8000)

while true
  Thread.start(server.accept) do |s|
    while line = s.gets.chomp
      case line
      when /^GET/
        puts line
      when /^\S+?\: \S+$/
        puts line
      else
        break
      end
    end
    s.close
  end
end

サーバ起動:

$ ruby ws_handshake.rb # 8000/tcpで待ち受け

ブラウザからの出力

ここでは、ChromeJavaスクリプトコンソールから、先ほど開いたサーバポートにWebSocketプロトコルで接続してみます。

> new WebSocket('ws://localhost:8000/test');

すると、先ほどサーバを起動したターミナル上に、以下のように表示されます。

GET /test HTTP/1.1
Upgrade: websocket
Connection: Upgrade
Host: localhost:8000
Origin: chrome://newtab
Sec-WebSocket-Key: l25AVE4wwuIb6Ed/qlreGg==
Sec-WebSocket-Version: 13
Sec-WebSocket-Extensions: x-webkit-deflate-frame

リンク先の解説によると、これだけではWebSocketプロトコルバージョンは特定できず、hybi-13〜RFC 6455のいずれかのバージョンであることが分かることになります。

メモ: node.jsでHello world

コンソール版Hello world

hello.js:

console.log("Hello, world");

これをターミナル上で実行すると "Hello, world" と表示される。

$ node hello.js
Hello, world
$

Webサーバ版Hello world

「参考」に挙げたハンズオン資料中のコード例ほぼそのままですが。

hello_server.js:

var http = require('http');

var server = http.createServer(function(req, res) {
  res.writeHead(200, {'Content-Type': 'text/plain'});
  res.write('Hello, world\n');
  res.end();
});
server.listen(8000);

ターミナル上で hello_server.jsを実行

$ node hello_server.js

この状態で、同じホスト上のWebブラウザから http://localhost:8000/ に接続すると、ブラウザ上に "Hello, world" と表示される。

『弱者99%社会』

2章「現役世代をどう支えるか」を中心にざっと拾い読み。

弱者99%社会 (幻冬舎新書)

弱者99%社会 (幻冬舎新書)

以下は自分なりの解釈を含んでいるので、必ずしも本文の内容とは一致していない可能性があります。

日本的雇用と社会

伝統的に (高度成長期〜1980年代くらい?) 日本における正社員は以下のような性質を持つ。

  • 安定した雇用 (主に解雇要件の厳しさに起因)
  • 年功型の賃金上昇
  • 充実した社会保障、社会的信用
  • 異動、転勤、長時間残業/休日出勤など、過酷な勤務内容

一方、アルバイト、パートなどの非正規雇用は、これとは対称的に、以下のような状況にある。

  • 不安定な雇用
  • ほとんど上昇しない賃金
  • 薄い社会保障、低い社会的信用

20年前くらいまでは、夫が正社員として安定した収入を得て、妻がパートなどの形で補助収入を得るという形で、それなりにうまく回っていた。しかし、近年の正規雇用の縮小とともに、この構図が成り立たなくなってきた。狭き門となった正規雇用を獲得できないと、家庭を築くのが困難というのが今の状況。また、正社員としては、「少数精鋭」化のために要求される能力が高度化し、疲弊しやすい状況になっている。

この状況に対して濱口桂一郎氏が提唱しているのが、「ジョブ型正社員」という雇用形態。

  • 雇用契約の中で、職務、労働時間、就業場所が規定される (→契約で規定された仕事以上のことはする必要がない)
  • 雇用期間の限定はない (会社から見ると、仕事がなくなった時点で解雇可能。逆に雇用期間の上限もない)

ジョブ型正社員は (日本型) 正社員と非正規社員の中間的な存在であり、正社員として働き続けるのが無理な人、および非正規社員からステップアップしたい人の両方にとっての選択肢となる。

(以下感想)

ジョブ型正社員の可能性について、思いついたことを列挙してみます。

  • ジョブ型正社員のような制度は、確かに多くの人にとっては適した選択肢になりうると思う半面、現状の延長として考えると、結局ブラック職場のような問題が発生するのではないかという気もする。
  • 現状でも、正社員の立場でもそれほど疲弊する状況でない人も多い (であろう) ことからの類推で、結局ジョブ型正社員が成立するかどうかは、個別の業界や会社の状況に依存するのではないかと思う。
  • 企業にとってジョブ型正社員の導入にどのような合理性があるのかが1つのポイントと思う。企業が戦力とみなすような高度な専門性を持っていて、かつ正社員として働くことができない/希望しない人については、ジョブ型正社員として雇用する必然性がある。

Himawari Readerその後

以前取り上げた、AndroidEPUBリーダーアプリ「Himawari Reader」にアップデート来ました。
前回の記事→ Himawari Readerに期待 - m-kawato@hatena_diary

https://market.android.com/details?id=jp.green_fld.himawari

このバージョンの新機能:
2012/1/30 Ver1.1.0(build 2012001)
Nightモードを追加
フォント切り替え機能を追加(外部フォント利用可能)
文書表示時、全画面化するように変更
画像が正しく表示されない場合があった問題を修正

以前のバージョンでは、手持ちの電子書籍の埋め込み画像がうまく表示されないという問題がありました。

では早速新バージョンで同じタイトルを表示してみます。

おおっ、ちゃんと表示されている!

フォント切り替え機能はまだ試していませんが、これは普通に常用できるんじゃないでしょうか。

OAuth認証メモ

過去日記では書いていなかったので、復習を兼ねてRubyのoauthライブラリを使ったOAuth認証Twitter APIの呼び出しを試してみます。
FacebookGoogle系のAPIはOAuth 2.0が採用されているようですが、Twitter APIではまだAuth 1.0のみ正式対応なので、今回はOAuth 1.0を使います。

やったこと

Rubyのoauthライブラリは、Railsと組み合わせて、認可ページ (○○アプリがあなたのアカウントを利用することを許可しますか?) にリダイレクト→呼び出し元のページにリダイレクトという動作が基本のようですが、ここではRailsなしで試す前提で、認可ページからPINコードを発行する形で動かしてみます。

  1. Twitterアプリケーション管理ページから、アプリケーションのConsumer key, Consumer secretを取得
  2. 認可用スクリプト (oauth_auth.rb) から認可ページURLを出力
  3. ブラウザから認可ページURLにアクセスし、PINコードを発行
  4. 認可用スクリプトにPINコードを入力 → アクセストークン発行
  5. API呼び出しスクリプト (twitter_api.rb) にアクセストークンを入力し、Twitter APIを呼び出し

テスト環境

oauthは公式のドキュメントが充実していないので結構やっかいでした…

Consumer key/secret取得

Twitterアプリケーション管理ページには、http://dev.twitter.com/apps あるいはTwitterの設定ページ→アプリ連携→開発者 で入れます。

ここで、登録したアプリのConsumer keyとConsumer secretが参照できます。

アクセストークン発行

認可用スクリプトoauth_auth.rbの流れは以下のようになります。

  1. 取得したConsumer key/secretからリクエストークン (RequestToken) 作成
  2. (ブラウザから、リクエストークンに含まれる認可用URLにアクセス→PINコード発行)
  3. RequestToken#get_access_token にPINコードを渡して、アクセストークン (AccessToken) 発行
  4. AccessTokenオブジェクトに含まれるアクセストークンとシークレットを出力

ここで取得したAccessTokenオブジェクトを直接使ってTwitter APIを呼び出すこともできますが、一旦発行したアクセストークンは後で使い回すことができるので、ここで出力したアクセストークンを別スクリプトtwitter_api.rbで使うことにします。

oauth_auth.rb:

require 'oauth'

CONSUMER_KEY = "Consumer Key"
CONSUMER_SECRET = "Consumer Secret"

consumer = OAuth::Consumer.new(CONSUMER_KEY, CONSUMER_SECRET,
                               :site => "http://twitter.com")

request_token = consumer.get_request_token 
puts "authorize_url = #{request_token.authorize_url}"

print "type pin: "
pin = gets.chomp
access_token = request_token.get_access_token(:oauth_verifier => pin)
puts "oauth token: #{access_token.token}"
puts "token secret: #{access_token.secret}"

このスクリプトを実行すると、"authorize_url = " に続いて認可用URLが出力されます。ブラウザのアドレスバーにこのURLを入れると、おなじみの認可画面が現れ、「連携アプリを認証」をクリックするとPINコードが出力されます。このPINコードを、"type pin: " のプロンプトに入力すると、リクエストークン (oauth token) とシークレット (token secret) が出力されます。

Twitter API呼び出し

基本的には、先ほど取得したAccessTokenオブジェクトを使って、

response = access_token.get(url)

のようにすれば、OAuth認証ヘッダつきのHTTPリクエストが発行されます。

前述した通り、一旦発行したアクセストークンを使い回す目的から、Consumer Key/Secret、Access Token/Secretの組からAccessTokenオブジェクトを生成し、そのAccessTokenを使ってTwitter APIを呼び出してみます。

twitter_api.rb:

# -*- coding: utf-8 -*-
require 'oauth'
require 'json'
require 'pp'

CONSUMER_KEY = "Consumer Key"
CONSUMER_SECRET = "Consumer Secret"
OAUTH_TOKEN = "Access Token"
OAUTH_TOKEN_SECRET = "Token Secret"

consumer = OAuth::Consumer.new(CONSUMER_KEY, CONSUMER_SECRET,
                               :site => "http://twitter.com")

access_token = OAuth::AccessToken.from_hash(consumer,
        :oauth_token => OAUTH_TOKEN,
        :oauth_token_secret => OAUTH_TOKEN_SECRET
)

response = access_token.get("http://api.twitter.com/1/statuses/home_timeline.json")
result = JSON.parse(response.body)
pp result

成功すると、oauth_auth.rb実行途中にブラウザからログインしたTwitterアカウントのタイムラインが出力されるはずです。