sashimi4’s diary

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

Androidデバイスでディスプレイ解像度変更

前回↓のような記事を書いた通り(?)、私はディスプレイを広く使いたくてしょうがない人間です。 sashimi4.hatenablog.com

そしてAndroidバイスに於いても解像度を変更する手段を発見したので記します。

Android開発環境(adb環境)をセットアップ

省きます。 For geek とつけたのはそういう意味です。 なお、 adbさえあればいいミニマルな環境構築方法は他の方もよく紹介されていますので、ググっていただければ簡単に見つかるかと思います。

adbコマンド実行

規定(≒現在)の解像度を確認。

$ adb shell wm size
Physical size: 720x1280

好みの解像度を設定。 & 任意解像度でオーバーライド出来ているか確認。

$ adb shell wm size 1080x1920

~

$ adb shell wm size
Physical size: 720x1280
Override size: 1080x1920

この端末は4Kは無理でした 😇

$ adb shell wm size 2160x3840

~

$ adb shell wm size
Physical size: 720x1280
Override size: 1440x2560

こんな感じで弄れます。

使ってみたメモ

  • 本変更は端末を再起動しても持続されるようです。
  • IME設定でキーの高さを最大にすると操作性が上がります。
  • 画面の隅の方をタッチすると、タッチ補正により意図しない座標がタッチされることがありました。おそらくdpiの変更により補正条件に悪影響が出ているのでしょうかね…

とりあえず以上です。

コマンドラインからMacOSの画面解像度を変更する

DisplayMenuとかQuickResといったGUIアプリも有るし持っているんだけど、コマンドラインからいじりたくなったのでメモ。

Installation

$   brew install homebrew/cask/cscreen
==> brew cask install homebrew/cask/cscreen
==> Satisfying dependencies
==> Downloading http://www.pyehouse.com/wp-content/uploads/2012/09/cscreenIntel.dmg
######################################################################## 100.0%
==> Verifying checksum for Cask cscreen
==> Installing Cask cscreen
==> Linking Binary 'cscreen' to '/usr/local/bin/cscreen'.
🍺  cscreen was successfully installed!

Usage

Show display list

$ cscreen -l
DisplayID  Index     Depth     Width     Height  Refresh
 4280a40       1        32      2560       1600     0
use -h to display all usage options

Show available settings for display

$ cscreen -s1 -v
DisplayID  Index     Depth     Width     Height  Refresh
 4280a40       1        32      2560       1600     0
 4280a40       2        32      1280        800     0
 4280a40       3        32      2048       1280     0
 4280a40       4        32      1650       1050     0
 4280a40       5        32      1440        900     0
 4280a40       6        32      1152        720     0
 4280a40       7        32       840        524     0
 4280a40       8        32      1024        768     0
 4280a40       9        32       800        600     0
 4280a40      10        32       640        480     0
use -h to display all usage options

※ ディスプレイが1つしか無いので -s1 は省略可。

MacBook Pro内蔵のRetinaディスプレイなんですが、リフレッシュレートが見えませんね... :thinking_face:

Set display as you like!

$ cscreen -s1 -x 2560 -y 1600

私はメインでMacBook Pro (Retina, 13-inch, Early 2015)を使っているので、上記のコマンドでDotByDot表示できます。

その他は -d オプションでDepthや -r オプションでRefresh rateを設定できるようです。 詳しくは -h オプションでヘルプを見ると良いと思います。

比率が合うわけない 1920x1080 とか、その他中途半端な値等を指定すると、 cscreen -s1 -v で表示された中の近似値が選ばれるみたい? ちなみにドット数を超えた解像度は設定できない模様。他のGUIアプリだと設定できるんですけどね…。

以上です。

さくらのクラウドでVPN(L2TP/IPsec PSK)サーバを簡易構築

利用ツール/技術

手順

# 注意
- 本手順を適用すると、サービス利用料が発生します。
- 一身上の都合により英語版コントロールパネルを利用しています。
- 本スクリプトの利用により損害が発生しても、私は一切の責任を負いかねます。

※ 会員登録方法等については省略します。詳しくは下記リンク先をご覧ください。 cloud.sakura.ad.jp

今回は、設定を自動化するためのスクリプトを用意しました。
このスクリプトさくらのクラウド の "スタートアップスクリプト" 機能に通すことで設定を自動化することができます。

スタートアップスクリプト機能とは、サーバ起動時に任意スクリプトを実行し、 パッケージのインストールや各種設定作業の自動化などを簡単に実現できる機能です。 本手順では、さくらのクラウド側で用意されているものではなく、VPNサーバのセットアップ用のカスタムスクリプトを登録して使います。

さくらのクラウドは時間課金ですので、 設定を自動化 して、 使いたいときに立て使わないときは削除 すればコスト面もうれしいですねっ。

スタートアップスクリプトを登録

さくらのクラウド コントロールパネルにログインします。

f:id:sashimi4:20180423204927p:plain IaaSを選択します。

f:id:sashimi4:20180423205551p:plain 設定 > Script の順に開きます。

f:id:sashimi4:20180423210247p:plain ↓のスクリプトを↑の画像のようにコピペします。


以上でスクリプトの登録は完了です。

サーバを作成(スタートアップスクリプト実行)

f:id:sashimi4:20180423210514p:plain サーバを作成します。

f:id:sashimi4:20180423210558p:plain デフォルトでSimple modeにチェックが入っていますが、 必ず外します

スペックは好みに設定して大丈夫です。 f:id:sashimi4:20180423210804p:plain Disk sourceArchive を選択し、 Ubuntu 16.04 を選択します。

f:id:sashimi4:20180423211123p:plain 次に、 Modify disk にて、先程追加したスクリプトを選択します。 すると、VPN接続の認証情報の入力フォームが表示されるので、任意のものを入力します。

後は作成ボタンを押すだけで、スクリプトが自動で設定を行います。

動作確認

f:id:sashimi4:20180423211641p:plain サーバ一覧を開き、サーバが起動していることを確認します。 (起動していなかったら起動します。)

今回はMacで動作確認をします。

f:id:sashimi4:20180423212420p:plain ネットワーク設定からVPN設定を追加します。

f:id:sashimi4:20180423212507p:plain 次にサーバのIPアドレスと、サーバ作成時に設定したユーザ名を入力します。

続いて認証設定を開き、 f:id:sashimi4:20180423212601p:plain 同じく、サーバ作成時に設定したパスワードと事前共有鍵(PSK)を入力・設定します。

後は接続ボタンを押せば繋がるはずです。

f:id:sashimi4:20180423212707p:plain 送受信できていることがわかります。

なお、好み・環境によっては、 f:id:sashimi4:20180423212310p:plain f:id:sashimi4:20180423212903p:plain Advanced から、すべてのトラフィックVPNを通すように設定しても良いでしょう。

f:id:sashimi4:20180423212932p:plain これでCMANさんなんかで確認すると、ゲートウェイIPがさくらのクラウドIPアドレスになっていることがわかります。

手順は以上です。

Have a nice VPN life!

Ubuntuのiptablesを永続化する

configファイルを作成

デフォルト設定に加えたいものがある場合

e.g.

$ sudo iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE # 任意の設定の例
$ sudo sh -c "iptables-save > /etc/iptables.rules"

希望の設定がある場合

e.g.

$ sudo bash -c "cat >/etc/iptables.rules" <<EOF
# 以下、任意の設定の例
*filter
:INPUT ACCEPT [2426:480164]
:FORWARD ACCEPT [1902:649674]
:OUTPUT ACCEPT [2166:1094891]
:f2b-sshd - [0:0]
-A INPUT -p tcp -m multiport --dports 22 -j f2b-sshd
-A INPUT -p tcp -m multiport --dports 22 -j f2b-sshd
-A f2b-sshd -j RETURN
-A f2b-sshd -j RETURN
COMMIT
# Completed on Thu Apr 19 16:00:35 2018
# Generated by iptables-save v1.6.0 on Thu Apr 19 16:00:35 2018
*nat
:PREROUTING ACCEPT [810:66915]
:INPUT ACCEPT [58:8731]
:OUTPUT ACCEPT [19:1213]
:POSTROUTING ACCEPT [0:0]
-A POSTROUTING -o eth0 -j MASQUERADE
COMMIT
EOF

起動時の読み込み設定

$ sudo sed -ie "/^iface eth0.*$/a \  pre-up iptables-restore < /etc/iptables.rules" /etc/network/interfaces

これで eth0がupするときに設定が読み込まれます。 if名は適宜変更してください。

参考 : IptablesHowTo - Community Help Wiki

"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.