"No Internet Connection Dialog" in Android
「インターネットに接続できません。設定を確認してください。」っていうあのダイアログをサクッと実装します。
地味なのでqiitaではなくここに書きます 😇
大まかな実装
- パーミッション :
ACCESS_NETWORK_STATE
を追加。
app/src/main/AndroidManifest.xml
... <uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> ...
- ステータスチェックをするメソッドを追加
任意の場所(*)に追加します。
... public boolean isOnline() { ConnectivityManager connectivityManager = (ConnectivityManager) getApplicationContext().getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo netInfo = null; if (connectivityManager != null) { netInfo = connectivityManager.getActiveNetworkInfo(); } return netInfo != null && netInfo.isConnected() && netInfo.isAvailable(); } ...
- 接続状況を判定&ダイアログで設定画面を案内
任意の場所(*)で先程のメソッドで判定し、オンラインでなければダイアログで設定画面を案内します。
if (!isOnline()) { new AlertDialog.Builder(this) .setTitle("No internet connection") .setMessage("A network connection is required.") .setIcon(android.R.drawable.ic_dialog_alert) .setPositiveButton("Open wireless settings", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { startActivity(new Intent(Settings.ACTION_WIFI_SETTINGS)); } }) .show(); return; }
動作
※ サンプルはMainActivityで判定するようにしました
機内モードで起動すると、ダイアログが表示されます。
positiveButton押下で、設定画面のWi-Fi設定画面へ移動します。
想定した動作はバッチリです。
任意の場所(*) について補足
主に以下のいずれかで行うことになるかと思います。
- アプリ起動時に最初に呼ばれるActivity
- MainActivity
- スプラッシュスクリーンのActivity
- 基底Activity方式ならBaseActivity
- Applicationクラス
ActivityLifecycleCallbacks
を実装して、onActivityResumed(...)
辺りで判定すると、漏れがない感じでしょうか。
以上です。
イースターエッグ等でのAndroidのボタン連打検知について
ふと、いま作っているアプリにイースターエッグを入れようと思い、ボタン連打の検知について簡単に考えてみました。
一番単純な、ボタンを一定回数/速度で連打すると何かが出てくるタイプです。
雑にやってみた
public class MainActivity extends AppCompatActivity { public static long CLICK_LIMIT_INTERVAL = 3000; private int count = 0; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab); fab.setOnClickListener(new View.OnClickListener() { @Override public void onClick(final View view) { count++; if (count >= 10) { Snackbar.make(view, "Wow!!!", Snackbar.LENGTH_LONG) .setAction("Action", null).show(); count = 0; return; } new Handler().postDelayed(new Runnable() { public void run() { if (count > 0) { count--; } } }, CLICK_LIMIT_INTERVAL); } }); } ...
雑〜にこんな感じで書いてみました。(プロトタイピングなのでfabかつMainActivityでやっています。) 3秒間で10回タップしないといけないようになっています。
ゆっくり押していると、10カウント到達前に最初に押したボタンからカウントが無効化(--;)されていく仕組みです。 単純で微妙に穴がありそうですが、とりあえずこれでもいいかなと思います。
おまけ : 本家はどうなっているか覗いてみた
本家イースターエッグ
最小3回のタップで行けるようです。
軽くトレースした感じ、最初のタップから3回目まで500msという制限になっているようです。たぶん。
System.arraycopy(...)
とか久しぶりに見た…。
開発者向けオプションを表示するアレ
Android4.2以降は開発者向けオプションが隠れていて、ビルド番号を連打しないと表示されないのは皆さんご存知かと思います。
こちらは、インターバル関係なしに7回タップすれば良いようですね。
もう一度やりたくなったら
もう一度開発者向けオプションを非表示にしたい場合は、 設定アプリ
の詳細から データを消去
を行うことで可能のようです。
以上、メモ書きでした。
Fabric Crashlytics から Firebase Crashlytics に移行しました
※ 手順を示す記事ではありません。単なるボヤキです。
経緯
GoogleがFabricを買収し、FirebaseにFabricと同等の機能の移行が続いています。
何れ完全にFirebaseに乗るのだろうから、今のうちにやっておこうと思い、移行を行いました。
(後述しますが、Fabricを使うそのまた前はFirebase::Crash-reportingを使っていたので、さっさとFirebaseに戻ってしまいたいという気持ちがありました。)
やったこと
依存関係の記述を修正
Fabric関連の依存関係の記述を取り払い、Firebase CrashlyticsのGet startedの内容通りに記述し直しました。
https://firebase.google.com/docs/crashlytics/get-started
Fabric Crashlyticsと使用感は変わらず、コードもほぼそのままで動作しました。
リアルタイム通知設定
元々Firebase CrashreportingからFabric Crashlyticsに移行した理由は、Slack通知のインテグレーションがあったことが主な理由でした。
(「そんなに頻繁にクラッシュする様なアプリ作るなよ!」というコメントは勘弁してください…)
FirebaseにはFunctions(まんまGCP Cloud Functions)という機能があるので、そこにSlack通知のスクリプトをデプロイしました。
参考 : https://firebase.google.com/docs/crashlytics/extend-with-cloud-functions
ほぼほぼこちらのサンプルと同様のものを利用しています。
functions-samples/crashlytics-integration/slack-notifier at master · firebase/functions-samples · GitHub
利用料
気になるのはお値段ですが。
Spark(無料)プランではFunctionsから外部への疎通ができないので、現在Blaze(従量課金)プランを利用しています。
料金シミュレータによれば、 2,000,000 invocations
使っても無料とのことなので、
おそらくずっと無料、多少はみ出ても数十円から数百円程度になりそうです。(この解釈で合ってるだろうか…)
これでFabricに思い残すことは何もありません!
Goodbye, Fabric.
ネットワーク越しのADB接続をスクリプト化
業務でTOUGHPADに関するアプリ開発を行っているのですが、MicroUSBコネクタの接触不良が激しく… 端末をちょっと触っただけでも接続が瞬断してプロセスからデバッガがデタッチされたりと、仕事にならないためADBをWi-Fi経由で接続しています。
常時ADBを無線で接続するとなると、コマンドを打つのが段々と面倒になってきたのでスクリプトを書きました。
スクリプト
一応これを毎日使っています。
$ cat ~/adb_ota.sh # パスは任意で #!/bin/bash # adb kill-server device_ip=`adb shell ip a | grep wlan0 | grep -oE '([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})' | head -n 1` adb tcpip 5555 adb connect ${device_ip} adb devices
※ MacOSにて動確済
適当に Over The Air
で ota
です。
使い方
$ adb devices List of devices attached HOGEHOGE device
現在の状態。 USBで接続されている端末が確認できる。
$ ~/adb_ota.sh restarting in TCP mode port: 5555 connected to 172.xx.xx.233:5555 List of devices attached 172.xx.xx.233:5555 device
以上。
memo: Android Screen Monitor起動用のalias
環境
設定
$ uname -v Darwin Kernel Version 16.7.0: Wed Oct 4 00:17:00 PDT 2017; root:xnu-3789.71.6~1/RELEASE_X86_64 $ cat ~/.bashrc ... # Android Screen Monitor alias asm='java -jar /Users/sashimi/Library/Android/sdk/tools/asm.jar $ANDROID_HOME' ...
TOUGHPAD(FZ-N1/FZ-X1)のバーコードリーダを制御する
最近はこの類を"スマートターミナル"と呼ぶのでしょうか?
Panasonic製の頑丈端末TOUGHPAD(FZ-N1/FZ-X1)のバーコードリーダを制御してみた記録を残したいと思います。
TOUGHPAD SDK内にサンプルコードはあるのですが、 Fragment
で書かれているので Activity
に落としてみました。
Qiitaに書こうか迷いましたが、限りなく需要がなさそうなのでここに書くことにしました。
製品レビューっぽいことは行いません。
詳細はPanasonicの公式ページを参照ください。 panasonic.biz panasonic.biz
必要なもの
- PC
- TOUGHPAD本体(FZ-N1/FZ-X1)
実装手順
Android Studioで新規プロジェクトを作成
手順は省略。
TOUGHPADライブラリ読み込み
TOUGHPAD SDKをダウンロードし、 Toughpad.jar
をプロジェクトの libs
(無ければ掘る)にコピー。
.exe
で落ちてくるので、MacやLinuxをお使いの際はなんとかしてWindowsで展開してください…。
app
モジュールの方の build.gradle
に下記記載があることを確認。無ければ追記。
(AndroidStudioのバージョンによっては自動記述されない時期があったため。)
dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) ...
バーコード読み取りClass(Activity)を作成
TOUGHPAD SDK同梱のサンプルコードをそのまま Activity
に落としたものです。
ダラダラと書いてありますが要約すると、
バーコードを読み取りたい画面( Activity
)で BarcodeReadableActivity
を継承すると、
onRead(BarcodeData barcodeData) {...}
コールバックで読み取り値を受け取れるようになります。
ということです。
読み取り結果を受け取ってみる
レイアウト
コード
以上の実装で、簡単に読み取り値を受け取れます。 かなり雑ですが、こんな感じです。
サンプルコードを GitHubにあげています。
以上です。
マイクラマルチサーバーの入退室をSlackに通知する
もっと頑張ればLightweightになる気がしているんですが、妥協で運用しているのでなかなか手間がかかる方法になっています。
本記事の内容は非推奨とします。
新しく書いたこちらの記事をご参照ください。
sashimi4.hatenablog.com
どうも、おさしみです。 今回は、下記記事のおまけで、タイトルの通り、やっていきたいと思います。 sashimi4.hatenablog.com
※ 前回とは違い、もはやエンジニアでないと理解できない内容になっていると思います。 ご参考までに(強め)。
手順(ざっくり)
- Rubyをインストール
2.3を使用します。 私はanyenvからのrbenvでインストールしました。
# ruby -v ruby 2.3.0p0 (2015-12-25 revision 53290) [x86_64-linux]
- Guard(Ruby gem)をインストール
$ gem install guard-rspec --no-ri --no-doc $ gem install guard-shell --no-ri --no-doc
と言った感じでインストールします。
- Guardfileを設置
マイクラのサーバーのログが溜まる場所と同ディレクトリに設置します。
$ cat Guardfile guard :shell do ll = '' watch(/latest.log/) {|m| # regexp joined|left|drown|slain ll = `tail -n 1 #{m[0]}` if ll.include?('joined') || ll.include?('left') message = ':white_check_mark: ' + ll.gsub(/(\r\n|\r|\n|\f)/,"") if ll.include?('joined') message = ':black_square_for_stop: ' + ll.gsub(/(\r\n|\r|\n|\f)/,"") if ll.include?('left') message = "[マイクラ鯖の通知だよ!] #{message}" channel = '#minecraft' username = 'Minecraft' icon = ':minecraft:' token = 'SLACK_INCOMING_WEBHOOK_TOKEN' cmd = %Q{curl -X POST --data-urlencode 'payload={"channel": \"#{channel}\", "username": \"#{username}\", "text": \"#{message}\", "icon_emoji": \"#{icon}\"}' https://hooks.slack.com/services/#{token}} `#{cmd}` unless message.nil? end } end
こんな感じのファイルを設置します。
SLACK_INCOMING_WEBHOOK_TOKEN
の部分は、ご自分のSlackチームでIncoming-Webhookを追加・設定し、トークンで置き換えてください。
- Guardを実行
$ guard -p -l 5
といった感じで実行します。 screenセッション上などで実行すると良いと思います。
以上で設定が完了するはずです。
結果
マイクラへjoin/leftすると、このように通知がされるはずです!
余談
Guardはファイルを監視し、差分を検知した時に任意のスクリプトを実行できます。 通常は、RSpecなどのテストを駆動するために用いるんですが…こういう使い方もできなくはないです。 まあこのためだけにRubyやらなにやらをセットアップするのは微妙ですね…。 CRONでもwatchでもなんでも良いんですけどね…。
はい、ざっくりですが、以上です。 何かあればコメントで。批判は頂けません><。