2014/03/24

Android:SAFの複数ファイル選択モードと要ログインサービスのために

Android4.4で導入されたStorageAccessFramework(SAF)について。
SAFが導入されたことでファイルブラウズ機能の提供が非常に手軽になりました。

SAFでは複数ファイル選択モードが具備されています。
当該モードを使用するにはIntent Extraとして下記を設定します。
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, flag);
SAFの選択UIでファイル名を長タップすることで、複数選択モードに移行します。

複数選択モードのonActivityResultについて。
単一選択モードではIntent の data に選択ファイルのURIが格納されますが、
複数選択モードではIntent の ClipData にURIが格納されています。
ClipData clip = data.getClipData();

Uri[] contentUri = new Uri[clip.getItemCount()];
for (int i = 0; i < clip.getItemCount(); i++) {
    contentUri[i] = clip.getItemAt(i).getUri();
}

話は変わって。

SAFのセキュリティについて。
SAFは対象のファイルがオンラインストレージ上にあるのか、ローカルストレージ上に
あるのかも隠蔽しようとします。
サービスによってはオンラインストレージ上のファイルを閲覧するのにログインを求めるケースがあります。
これをSAF上で実現するためには、DocumentProvider.queryRootを実装する際に
ユーザが非ログイン状態の場合は空のCursorを返すことで実現できます。
public Cursor queryRoots(String[] projection) throws FileNotFoundException {
...
    if (!isServiceProvide()) {
        return emptyCursor;
}
サービス提供の状態に変化(非ログイン状態からログイン状態へ移行等)があった場合、
getContentResolver.notifyChangeによる変更通知により、SAFの情報を更新します。
setviceStateChanged();
getContentResolver().notifyChange(DocumentsContract
        .buildRootsUri(AUTHORITY), null);
以上です。
2013/09/17

Android:ActionBar下部にProgressBarを表示


上図のようなActionBarの直下にプログレスバーを表示するUIがあります。
ActionBarの機能かと思ったのですが、どうもそうではなさそうなので自作しました。
# 類似のPJにPullToRefreshがあります

まずはActionBar下部に表示される影を消します。
これがあると、ActionBarとプログレスバーの間に隙間ができてしまいます。
<activity
    android:name="yuki312.android.actionbarprogress.MainActivity"
    android:label="@string/app_name"
    android:windowContentOverlay="@null" >

次にプログレスバーを配置するためのレイアウトを定義。
画面最上部にプログレスバーを配置します。
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="0dp" >
    <ProgressBar
        android:id="@+id/view_actionbar_progress"
        android:layout_width="match_parent"
        android:layout_height="3dp"
        android:indeterminateDrawable="@drawable/ic_progress_indeterminate" />
</RelativeLayout>

indeterminateDrawableにプログレスバーの画像を指定します。
プログレスバーの画像はアニメーションさせるのが一般的です。
1コマ毎の画像を用意してアニメーションリソースを用意しても良いのですが、
リソース節約のため、ここではShapeで描画します。
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
    android:oneshot="false" >
    <item android:duration="50">
        <shape android:shape="rectangle" >
            <gradient
                android:angle="180"
                android:centerY="1.0"
                android:endColor="@color/progress_dark"
                android:centerColor="@color/progress_light"
                android:startColor="@color/progress_dark"
                android:type="linear" />
        </shape>
    </item>
    <item android:duration="50">
        <shape android:shape="rectangle" >
            <gradient
                android:angle="180"
                android:centerY="0.8"
                android:endColor="@color/progress_dark"
                android:centerColor="@color/progress_light"
                android:startColor="@color/progress_dark"
                android:type="linear" />
        </shape>
    </item>
    <item android:duration="50">
        <shape android:shape="rectangle" >
            <gradient
                android:angle="180"
                android:centerY="0.6"
                android:endColor="@color/progress_dark"
                android:centerColor="@color/progress_light"
                android:startColor="@color/progress_dark"
                android:type="linear" />
        </shape>
    </item>
    <item android:duration="50">
        <shape android:shape="rectangle" >
            <gradient
                android:angle="180"
                android:centerY="0.4"
                android:endColor="@color/progress_dark"
                android:centerColor="@color/progress_light"
                android:startColor="@color/progress_dark"
                android:type="linear" />
        </shape>
    </item>
    <item android:duration="50">
        <shape android:shape="rectangle" >
            <gradient
                android:angle="180"
                android:centerY="0.2"
                android:endColor="@color/progress_dark"
                android:centerColor="@color/progress_light"
                android:startColor="@color/progress_dark"
                android:type="linear" />
        </shape>
    </item>
    <item android:duration="70">
        <shape android:shape="rectangle" >
            <gradient
                android:angle="180"
                android:centerY="0.0"
                android:endColor="@color/progress_dark"
                android:centerColor="@color/progress_normal"
                android:startColor="@color/progress_dark"
                android:type="linear" />
        </shape>
    </item>
   
    <item android:duration="100">
        <shape android:shape="rectangle" >
            <gradient
                android:angle="180"
                android:centerY="0.2"
                android:endColor="@color/progress_dark"
                android:centerColor="@color/progress_normal"
                android:startColor="@color/progress_dark"
                android:type="linear" />
        </shape>
    </item>
    <item android:duration="100">
        <shape android:shape="rectangle" >
            <gradient
                android:angle="180"
                android:centerY="0.4"
                android:endColor="@color/progress_dark"
                android:centerColor="@color/progress_normal"
                android:startColor="@color/progress_dark"
                android:type="linear" />
        </shape>
    </item>
    <item android:duration="100">
        <shape android:shape="rectangle" >
            <gradient
                android:angle="180"
                android:centerY="0.6"
                android:endColor="@color/progress_dark"
                android:centerColor="@color/progress_normal"
                android:startColor="@color/progress_dark"
                android:type="linear" />
        </shape>
    </item>
    <item android:duration="100">
        <shape android:shape="rectangle" >
            <gradient
                android:angle="180"
                android:centerY="0.8"
                android:endColor="@color/progress_dark"
                android:centerColor="@color/progress_normal"
                android:startColor="@color/progress_dark"
                android:type="linear" />
        </shape>
    </item>
    <item android:duration="100">
        <shape android:shape="rectangle" >
            <gradient
                android:angle="180"
                android:centerY="1.0"
                android:endColor="@color/progress_dark"
                android:centerColor="@color/progress_normal"
                android:startColor="@color/progress_dark"
                android:type="linear" />
        </shape>
    </item>

</animation-list>
これで、ActionBar下部にプログレスバーが表示されます。

ソース+apkをgithubにアップしています。
https://github.com/YukiMatsumura/ActionBarProgress

以上です。