sashimi4’s diary

日々の雑多なメモを書きます

"No Internet Connection Dialog" in Android

「インターネットに接続できません。設定を確認してください。」っていうあのダイアログをサクッと実装します。
地味なのでqiitaではなくここに書きます 😇

大まかな実装

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で判定するようにしました
機内モードで起動すると、ダイアログが表示されます。 f:id:sashimi4:20180411184633p:plain

positiveButton押下で、設定画面のWi-Fi設定画面へ移動します。 f:id:sashimi4:20180411184653p:plain

想定した動作はバッチリです。

任意の場所(*) について補足

主に以下のいずれかで行うことになるかと思います。

  • アプリ起動時に最初に呼ばれる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カウント到達前に最初に押したボタンからカウントが無効化(--;)されていく仕組みです。 単純で微妙に穴がありそうですが、とりあえずこれでもいいかなと思います。

おまけ : 本家はどうなっているか覗いてみた

本家イースターエッグ

src/com/android/settings/deviceinfo/FirmwareVersionPreferenceController.java - platform/packages/apps/Settings - Git at Google

最小3回のタップで行けるようです。 軽くトレースした感じ、最初のタップから3回目まで500msという制限になっているようです。たぶん。 System.arraycopy(...) とか久しぶりに見た…。

開発者向けオプションを表示するアレ

Android4.2以降は開発者向けオプションが隠れていて、ビルド番号を連打しないと表示されないのは皆さんご存知かと思います。

src/com/android/settings/deviceinfo/BuildNumberPreferenceController.java - platform/packages/apps/Settings - Git at Google

こちらは、インターバル関係なしに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

利用料

気になるのはお値段ですが。

firebase.google.com

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 Airota です。

使い方

$ 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

スクリプト実行。 無事にWi-Fi経由で接続がされた。

以上。

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

必要なもの

実装手順

Android Studioで新規プロジェクトを作成

手順は省略。

TOUGHPADライブラリ読み込み

TOUGHPAD SDKをダウンロードし、 Toughpad.jar をプロジェクトの libs (無ければ掘る)にコピー。 .exe で落ちてくるので、MacLinuxをお使いの際はなんとかして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すると、このように通知がされるはずです! f:id:sashimi4:20171116230353p:plain

余談

Guardはファイルを監視し、差分を検知した時に任意のスクリプトを実行できます。 通常は、RSpecなどのテストを駆動するために用いるんですが…こういう使い方もできなくはないです。 まあこのためだけにRubyやらなにやらをセットアップするのは微妙ですね…。 CRONでもwatchでもなんでも良いんですけどね…。

はい、ざっくりですが、以上です。 何かあればコメントで。批判は頂けません><。