20210120のAndroidに関する記事は6件です。

【Android】センサーを使う方法

プログラミング勉強日記

2021年1月20日
一昨日の記事でAndroidのセンサーAPIについてまとめた。今日はAndroidのセンサーの使い方を簡単にまとめる。

Androidセンサーを使う方法

 Androidセンサーを使う処理を説明する。

1. SensorManagerを取得

 SensorManagerを取得するためには、getSystemServiceメソッドを使う。引数には、android.contentパッケージのContextクラスの定数SENSOR_SERVICEを指定する。

SensorManagerの取得
// SensorManagerインスタンス
private SensorManager sensorManager;

@Override
public void onCreate(Bundle savedInstanceState) {
  // SensorManagerのインスタンスを取得する
  sensorManager = (SensorManager) this.getSystemService(SENSOR_SERVICE);
}

2. イベントリスナーの実装

 イベントリスナーは、何かしらのイベントが発生したときに呼ばれるクラスである。センサーイベントには、SensorEventListenerインタフェースをActivityに実装して具体的な処理をする。
 SensorEventListenerインタフェースにはonAccuracycahngedとonSensorCahngedの2つのメソッドが定義されている。

イベントリスナーの実装
public class SensorActivity extends Activity implements SensorEventListener {


    @Override
    // センサーの精度が変更されると呼ばれる
    public void onAccuracyChanged(Sensor sensor, int accuracy) {

    }

    @Override
    // センサーの値が変化すると呼ばれる
    public void onSensorChanged(SensorEvent event) {

    }
}

イベントリスナーの登録と登録解除の方法

 リスナーの登録にはSensorManagerクラスのregisterListenerメソッドを使う。引数には、センサーイベントを取得するリスナー、取得するセンサーの種類、取得する頻度を設定する。

registerListener(SensorEventListener listener, Sensor sensor, int rate)

 イベントリスナーの登録解除には、SensorManagerクラスのunregisterListenerメソッドを使う。

イベントリスナーの登録を解除
protected void onPause() {
    super.onPause();
    if (sensorManager != null) {
        sensorManager.unregisterListener(this);
    }
}

参考文献

センサーを利用する / GETTING STARTED

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

HMSスマホでLINE CLOVA Assistantを有効にする手順と機能紹介

HMSスマホの音声アシスタント

音声アシスタントとは音声だけで端末を操作する機能です。

一般的に、Android端末ではGoogleアシスタントがプリインストールされ、使われています。ところが、ファーウェイの最新端末にGoogleのアプリがプリインストールされていないし、GMSも入っていないので、Googleアシスタントが利用できません。

ファーウェイは去年セリア(Celia)という音声アシスタント機能をリリースしました。しかし、残念ながら、日本語がまだ対応されておらず、日本もまだサポート地域に入っていません。

幸い、HMS端末で使える音声アシスタントはほかにあります。それはLINE CLOVA Assistantです。しかも、以下のHMS端末ではLINE CLOVA Assistantが標準搭載になっています

image.PNG

HMS端末でLINE CLOVA Assistantを有効にする手順

[設定] -> [アプリ] -> [デフォルトアプリ] -> [アシスタント機能と音声入力] -> [アシストアプリ] に入って、LINE CLOVA Assistantを選ぶだけです。

こちらはその手順の動画です:https://twitter.com/i/status/1351829028173320192

(LINE CLOVA Assistantを使うのに、LINE)

HMS端末のLINE CLOVA Assistantで何ができるか?

以下のできることの例です。

機能 コマンドの例
電話をかける 〇〇に電話かけて
通話履歴を表示する 通話履歴を表示して
スマホの設定を変更する Bluetoothをオンにして
アプリを起動する App Galleryを起動して
天気を調べる 今日の天気を教えて
事柄を調べる 〇〇について教えて
ニュースを知る ニュースを教えて
翻訳する ○○語に翻訳して
日時などを確認する いま何時
運行情報を調べる 山手線の運行情報を教えて
イベント情報を調べる イベント情報教えて

こちらはHMS端末でLINE CLOVA Assistantを使う動画です。

アプリ起動:https://twitter.com/i/status/1351829397662121986
百科事典:https://twitter.com/i/status/1351829528914522115
時間:https://twitter.com/i/status/1351829624880132100

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

スコープ関数のrun()関数を使わずに、関数式を使う方法

金田著「はじめてのandroidプログラミング 第5版」を使って、勉強しています。

 「第9章カウントダウンタイマーを作ろう」で使っているテクニックを解析してみます。
 スコープ関数のrun関数を関数式に直してみます。
 はじめはrun関数の意味が分からなかったので、まずはrun関数を使わず、インスタンスを作り、そのメソッド()を操作する古いやり方に書き換えようとしました。しかしSoundPoolクラスのコンストラクタが非推奨になっていたので、本書のとおりSoundPool.Builder()でインスタンスを作ることにしました。調べて行く過程でrun関数を使わずに、関数式で書けることが分かったので紹介します。

 以下、本書を持っている前提で説明します。本書を使って勉強中の方、一緒に勉強しましょう。

0.前提

 p253まで写経が済んでいるとします。

1.原型

 p253まで写経が済んでいる状態のコードを示します。説明に不要な部分は、著作権に配慮して省略しています。
 本書のやり方では、SoundPool.Builder()のrun()関数の中に、AudioAttributesのインスタンスを作り出すAudioAttributes.Builderが含まれています。

MainActicity.kt
class MainActivity : AppCompatActivity() {
    // 省略
    override fun onResume() {
        super.onResume()
        soundPool =
                SoundPool.Builder().run {
                    val audioAttributes = AudioAttributes.Builder().run {
                        this.setUsage(AudioAttributes.USAGE_ALARM)
                        this.build()
                    }
                    this.setMaxStreams(1)
                    this.setAudioAttributes(audioAttributes)
                    this.build()
                }
        // 省略
    }
    // 省略
}

2.AudioAttributes.Builderを、SoundPool.Builder()のrun関数の外に出す

 先ずは、SoundPool.Builder()のrun関数の中に含まれているAudioAttributes.Builderを、SoundPool.Builder()のrun関数の外に出します。なおrun関数の動作については、本書p127に書かれています。

MainActicity.kt
class MainActivity : AppCompatActivity() {
    // 省略
    override fun onResume() {
        super.onResume()

        val audioAttributes = AudioAttributes.Builder().run {    // (2)(1)をここへ移動する。(追記)
            this.setUsage(AudioAttributes.USAGE_ALARM)    // this.は省略可
            this.build()
        }

        soundPool = SoundPool.Builder().run {
            // val audioAttributes = AudioAttributes.Builder().run {    // (1)この部分を外に出す(削除)
            //    this.setUsage(AudioAttributes.USAGE_ALARM)
            //    this.build()
            // }
            this.setMaxStreams(1)
            this.setAudioAttributes(audioAttributes)
            this.build()
        }
        // 省略
    }
}

 ここで、 AudioAttributesやSoundPoolのインスタンスを作るのに、コンストラクタを用いることが非推奨であるから使えないので、このままAudioAttributes.Builder()、SoundPool.Builder()を使ってインスタンスを作ることとした。

3.関数型に変換する

 上記のコードを関数型に書き換えます。関数型に変換するにあたり、nyan のアプリ開発を参考にした。

MainActivity.kt
// 省略
    override fun onResume() {
        super.onResume()

        // 変換方法<参考> https://akira-watson.com/android/kotlin/soundpool-play.html>
        val audioAttributes = AudioAttributes.Builder()    // run()関数とthisを外し、関数をピリオド(.)連結する。
            .setUsage(AudioAttributes.USAGE_ALARM)
            .build()
        // val audioAttributes = AudioAttributes.Builder().run {    
        //     this.setUsage(AudioAttributes.USAGE_ALARM)    
        //     this.build()
        // }

        // 変換方法<参考> https://akira-watson.com/android/kotlin/soundpool-play.html>
        soundPool = SoundPool.Builder()    // run()関数とthisを外し、関数をピリオド(.)連結する。
            .setMaxStreams(1)
            .setAudioAttributes(audioAttributes)
            .build()
        // soundPool = SoundPool.Builder().run {
        //     this.setMaxStreams(1)
        //     this.setAudioAttributes(audioAttributes)
        //     this.build()
        // }

        // 省略
    }

// 省略

 第2項のrun()関数を使うやり方と第3項の関数式を使うやり方と、どちらが見やすいでしょうか?私は、電車ごっこのような、順繰りとタスクが進む関数式の方が、分かりやすく見やすいと思います。run関数を使うか、関数式を使うかの選択は、趣味の問題でしょうか?疑問が残ります。

3.蛇足

 見た目、汚らしいですがrun()関数の中で、関数を関数式で連結することも出来るみたいです。

MainActivity.kt
        soundPool = SoundPool.Builder().run {
            setMaxStreams(1)
                .setAudioAttributes(audioAttributes)     // ここから先を関数式で連結
                .build()
        }
MainActivity.kt
       soundPool = SoundPool.Builder().run {
            setMaxStreams(1)
            setAudioAttributes(audioAttributes)
                .build()     // これだけを関数式で連結
        }

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

スコープ関数のrun()関数を使わずに、ピリオドでメソッドを連結させる

金田著「はじめてのandroidプログラミング 第5版」を使って、勉強しています。

 「第9章カウントダウンタイマーを作ろう」で使っているkotlinの文法のテクニックを解析してみます。
 スコープ関数のrun関数を関数式に直してみます。
 はじめはrun関数の意味が分からなかったので、まずはrun関数を使わず、インスタンスを作り、そのメソッド()を一行1行、操作する古いやり方に書き換えようとしました。しかしSoundPoolクラスのコンストラクタが非推奨になっていたので、本書のとおりSoundPool.Builder()でインスタンスを作ることにしました。調べて行く過程でrun関数を使わずに、ピリオドでメソッドを連結できることが分かったので紹介します。

 以下、本書を持っている前提で説明します。本書を使って勉強中の方、一緒に勉強しましょう。

0.前提

 p253まで写経が済んでいるとします。

1.原型

 p253まで写経が済んでいる状態のコードを示します。説明に不要な部分は、著作権に配慮して省略しています。
 本書のやり方では、SoundPool.Builder()のrun()関数の中に、AudioAttributesのインスタンスを作り出すAudioAttributes.Builderが含まれています。

MainActicity.kt
class MainActivity : AppCompatActivity() {
    // 省略
    override fun onResume() {
        super.onResume()
        soundPool =
                SoundPool.Builder().run {
                    val audioAttributes = AudioAttributes.Builder().run {
                        this.setUsage(AudioAttributes.USAGE_ALARM)
                        this.build()
                    }
                    this.setMaxStreams(1)
                    this.setAudioAttributes(audioAttributes)
                    this.build()
                }
        // 省略
    }
    // 省略
}

2.AudioAttributes.Builderを、SoundPool.Builder()のrun関数の外に出す

 先ずは、SoundPool.Builder()のrun関数の中に含まれているAudioAttributes.Builderを、SoundPool.Builder()のrun関数の外に出します。なおrun関数の動作については、本書p127に書かれています。

MainActicity.kt
class MainActivity : AppCompatActivity() {
    // 省略
    override fun onResume() {
        super.onResume()

        val audioAttributes = AudioAttributes.Builder().run {    // (2)(1)をここへ移動する。(追記)
            this.setUsage(AudioAttributes.USAGE_ALARM)    // this.は省略可
            this.build()
        }

        soundPool = SoundPool.Builder().run {
            // val audioAttributes = AudioAttributes.Builder().run {    // (1)この部分を外に出す(削除)
            //    this.setUsage(AudioAttributes.USAGE_ALARM)
            //    this.build()
            // }
            this.setMaxStreams(1)
            this.setAudioAttributes(audioAttributes)
            this.build()
        }
        // 省略
    }
}

 ここで、 AudioAttributesクラスやSoundPoolクラスのインスタンスを作るのに、コンストラクタを用いることが非推奨であるから、AudioAttributes()やSoundPool()といった風にコンストラクタを使えないので、このままAudioAttributes.Builder()、SoundPool.Builder()を使ってインスタンスを作ることとした。

3.ピリオドで連結する方法に変換する

 上記のコードをピリオドでメソッドを連結した形式に書き換えます。ピリオドで連結する形式に変換するにあたり、nyan のアプリ開発を参考にした。

MainActivity.kt
// 省略
    override fun onResume() {
        super.onResume()

        // 変換方法<参考> https://akira-watson.com/android/kotlin/soundpool-play.html>
        val audioAttributes = AudioAttributes.Builder()    // run()関数とthisを外し、関数をピリオド(.)連結する。
            .setUsage(AudioAttributes.USAGE_ALARM)
            .build()
        // val audioAttributes = AudioAttributes.Builder().run {    
        //     this.setUsage(AudioAttributes.USAGE_ALARM)    
        //     this.build()
        // }

        // 変換方法<参考> https://akira-watson.com/android/kotlin/soundpool-play.html>
        soundPool = SoundPool.Builder()    // run()関数とthisを外し、関数をピリオド(.)連結する。
            .setMaxStreams(1)
            .setAudioAttributes(audioAttributes)
            .build()
        // soundPool = SoundPool.Builder().run {
        //     this.setMaxStreams(1)
        //     this.setAudioAttributes(audioAttributes)
        //     this.build()
        // }

        // 省略
    }

// 省略

 ピリオドで連結する形が使えるのは、AudioAttributes.BuilderクラスやSoundPool.Builderクラスのメソッドの戻り値が、AudioAttributes.Builder型やSoundPool.Builder型であるからである。例えばAudioAttributes.BuilderクラスのメソッドsetUsage()は、戻り値の型がAudioAttributes.Builderである。setUsage()のリファレンスを参照して頂きたい。

 さて、第2項のrun()関数を使うやり方と第3項のピリオドで連結するやり方とでは、どちらが見やすいでしょうか?私は、電車ごっこのような、順繰りとタスクが進むピリオドで連結する方が、分かりやすく見やすいと思います。run関数を使うか、関数式を使うかの選択は、趣味の問題でしょうか?疑問が残ります。

4.ピリオド連結を分解し、メソッドを一行一行処理する(2021/01/21追記)

 当初やり方が分からなかったが、落ち着いて考えたら方法を思いついたので記述する。
 ピリオドで連結していたメソッドを分解し、一行一行に変数を設けるようにコードを書き換える。

MainActivity.kt
        //   val audioAttributes = AudioAttributes.Builder()
        //       .setUsage(AudioAttributes.USAGE_ALARM)
        //       .build()
        val buildedAudioAttributes = AudioAttributes.Builder()
        val setUsagedAudioAttributes = buildedAudioAttributes.setUsage(AudioAttributes.USAGE_ALARM)
        val audioAttributes = setUsagedAudioAttributes.build()

        // soundPool = SoundPool.Builder()
        //    .setMaxStreams(1)
        //    .setAudioAttributes(audioAttributes)
        //    .build()
        val buildedSoundPool = SoundPool.Builder()
        val setMaxStreamsedSoundPool = buildedSoundPool.setMaxStreams(1)
        val setAudioAttributedBuildedSoundPool = setMaxStreamsedSoundPool.setAudioAttributes(audioAttributes)
        soundPool = setAudioAttributedBuildedSoundPool.build()

        // 省略

5.蛇足

 見た目、汚らしいですがrun()関数の中で、メソッドを連結することも出来るみたいです。第2項、第3項と比較してください。

【例1】

MainActivity.kt
        soundPool = SoundPool.Builder().run {
            setMaxStreams(1)
                .setAudioAttributes(audioAttributes)     // ここから先を関数式で連結
                .build()
        }

 
【例2】

MainActivity.kt
       soundPool = SoundPool.Builder().run {
            setMaxStreams(1)
            setAudioAttributes(audioAttributes)
                .build()     // これだけを関数式で連結
        }

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Android端末におけるMSALを使用したSSO認証

急に「これやりたいから調べてくれない?」と言われた自分用メモ

結論

https://docs.microsoft.com/ja-jp/azure/active-directory/develop/quickstart-v2-android
https://github.com/Azure-Samples/ms-identity-android-java
公式のクイックスタートとサンプルリポジトリのREADMEとソースを読むと良い。ドキュメントたくさんあるし自分がこれを書く必要なくない?

アプリの初起動

PublicClientApplication.createSingleAccountPublicClientApplication()を叩いてISingleAccountPublicClientApplicationインスタンスを取得する。
このインスタンスを使用して、サインインやサインアウト、アカウントの状態確認等ができる。

auth_config_single_account.jsonはMSALで使用する構成ファイル
Azureにアプリ登録した際のIDとか、リダイレクトURIとかの設定が記載されている。

PublicClientApplication.createSingleAccountPublicClientApplication(
    getContext(),
    R.raw.auth_config_single_account, // res/raw/auth_config_single_account.jsonのリソースID
    new IPublicClientApplication.ISingleAccountApplicationCreatedListener() {
        @Override
        public void onCreated(ISingleAccountPublicClientApplication application) {
            mSingleAccountApp = application;
            // 現在のアカウント状態を読み込む
        }

        @Override
        public void onError(MsalException exception) {
            displayError(exception);
        }
    });

アプリの構成が正しく読み込めたら、mSingleAccountApp.getCurrentAccountAsyncを呼び出して、現在のアカウントの状態を読み込む。
処理が終われば引数に設定したリスナーのonAccountLoadedが呼び出されて、引数にアカウント情報が入ってくる。
一度もサインインしていない場合は引数にnullが設定されるので、サインインする。

mSingleAccountApp.getCurrentAccountAsync(new ISingleAccountPublicClientApplication.CurrentAccountCallback() {
    @Override
    public void onAccountLoaded(@Nullable IAccount activeAccount) {
        if(activeAccount == null){
            // サインインの処理
        } else {
            // 必要であればトークンの更新
        }
    }

    @Override
    public void onAccountChanged(@Nullable IAccount priorAccount, @Nullable IAccount currentAccount) {
        // ログインアカウントを変更する場合に呼び出される
    }

    @Override
    public void onError(@NonNull MsalException exception) {
        displayError(exception);
    }
});

サインイン

サインインはmSingleAccountApp.signIn(activity, hint, scope, callback); を呼び出せばOK
activityは現在のアクティビティ
hintは事前入力用の文字列(nullable)
scopeは要求する権限
callbackはサインインの結果を受け取るリスナー

呼び出すとMSAL側のログインアクティビティが立ち上がってユーザーに認証を求めてくる。
サインインできればコールバックのonSuccessメソッドが呼び出される。

要望としてこっそりサインインさせたいんだけどって言われたけど
引数にアクティビティは必須だし、ログイン用のアクティビティが立ち上がるので
こっそりログインさせるのは無理そう

2回目以降の起動(トークンの取得・更新)

アプリ構成とログインしているアカウントの情報がコールバックの引数に入ってくるはずなので、そこから確認できる。
トークンを取得したい場合はmSingleAccountApp.acquireTokenメソッドか
mSingleAccountApp.acquireTokenSilentAsyncメソッドを呼び出すことで取得できる。
有効なアクセストークンがなくても、自動的にリフレッシュトークンを使用して更新してくれる。

基本はmSingleAccountApp.acquireTokenSilentAsyncを使用して、
エラーが発生する等のユーザが操作する必要がある場合にmSingleAccountApp.acquireTokenを使う感じだと思います。

トークンってどこに保存されているの

https://docs.microsoft.com/ja-jp/azure/active-directory/develop/msal-android-single-sign-on

IntuneもしくはMicrosoft Authenticatorが入っていて、会社等でデバイスを管理していれば、このアプリがトークンを保存している。

もしもIntuneとAuthenticatorが入っていない場合は、Androidで設定しているブラウザもしくはWebViewを使用する。
開くブラウザが異なると何度もサインインを求められるので注意。

その他ハマったポイント

リダイレクトURIについて

MSAL構成ファイルのリダイレクトURIはパーセントエンコーディングする必要があり、
AndroidManifest.xmlに記載するpathは、頭に/をつけてデコードした文字列を設定する必要がある。
例えば、以下のようなMSAL構成ファイルだった場合は

auth_config_single_account.json
{
  "client_id" : "0984a7b6-bc13-4141-8b0d-8f767e136bb7",
  "authorization_user_agent" : "DEFAULT",
  "redirect_uri" : "msauth://com.azuresamples.msalandroidapp/1wIqXSqBj7w%2Bh11ZifsnqwgyKrY%3D",
  "account_mode" : "SINGLE",
  "broker_redirect_uri_registered": true,
  "authorities" : [
    {
      "type": "AAD",
      "authority_url": "https://login.microsoftonline.com/common"
    }
  ]
}

以下のようなAndroidManifest.xmlになる。
(%2B+に、%3D=に変わっている。)

AndroidManifest.xml
<activity android:name="com.microsoft.identity.client.BrowserTabActivity">
    <intent-filter>
        <action android:name="android.intent.action.VIEW" />

        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />

        <data
            android:host="com.azuresamples.msalandroidapp"
            android:path="/1wIqXSqBj7w+h11ZifsnqwgyKrY="
            android:scheme="msauth" />
    </intent-filter>
</activity>

疲れたので終わり

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

直近のUnity開発で困ったことの逆引きメモ

メモ書きですが、どなたかのお役に立てれば幸いです。

NavMesh

NavMeshAgentのキャラクターの動きを改善する

こちらを使わせていただくとイイカンジに動きます。感謝!!
NavMeshAgentでよい感じにキャラクターを歩かせる - tanaka's Programming Memo

NavMeshをランタイムで動的に生成(Bake)する

NavMesh Componentsを入れるとNavMesh Surfaceが使える。
これをNavMeshを生成させたいオブジェクトに入れ、任意のタイミングで定期的にNavMeshをBakeさせればよい。
しかし、定期的にBakeすると、その都度Agent(キャラクター)の座標が変わってしまうことがあるので注意。

Unity:動的NavMeshの確認 - simplestarの技術ブログ

NavMeshAgentで浮いてしまう問題

[Navigation]ウィンドウの[Bake]→[Advanced]→[Height Mesh]のチェックをオンにする

Dynamically Fixing NavMeshAgent Base Offset? - Unity Answers

また、モデルの配置時は最低でもNavMeshが生成された地面等が必要。
地面がないと空中に浮いたまま移動してしまう。

UI

UIを貫通してRaycastしてしまうのを防止する

下記はARRaycastmanager向けのものだが、汎用的に使えそう。
なおPhysics.Raycastは常にUIを貫通するので注意。

AR Foundation ARRaycastmanager ray passing through UI,AR Foundation - ARRaycastmanager ray passing through UI - Unity Answers

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む