appcompat-22 のバグを回避する

# appcompat-22

Android 5.1 (API Level 22) と同時に [Android Support Library, revision 22](https://developer.android.com/tools/support-library/index.html#revisions) もリリースされましたが Android 4.4 以前に Material テーマを提供する appcompat-v7 も 22 になりました。

さっそく導入してみたところボタンのデザインがマテリアル化された感じでよりマテ度が上がっていていい感じです。

| appcompat-21 | appcompat-22 |
|--------------|--------------|
|![2015-03-16 13.05.05s.png](https://qiita-image-store.s3.amazonaws.com/0/39221/f01092dd-2647-f91f-1481-bc8eaf90cf6b.png)| ![2015-03-16 13.05.17s.png](https://qiita-image-store.s3.amazonaws.com/0/39221/56c42ec6-a4e3-9435-f00b-73c66987b271.png) |


が、例によって [バグもたくさん](https://code.google.com/p/android/issues/list?can=2&q=appcompat&colspec=ID+Type+Status+Owner+Summary+Stars&cells=tiles) あるようで、今回は特に致命的だったいくつかのバグの回避方法をメモしておきます。


# Fragment が切り替わらない

[Issue 160714 - android - AppCompat 22.0.0 FragmentTransaction replace bug - Android Open Source Project - Issue Tracker - Google Project Hosting](https://code.google.com/p/android/issues/detail?id=160714)

レイアウトの XML に直接 Fragment 名を記述していると、下記のような切り替えコードを書いても切り替わらない不具合がありました。

```java
getFragmentManager().beginTransaction()
                    .replace(some_id, some_fragment)
                    .addToBackStack(null)
                    .commit();
```

```xml:activity_gallery_image_picker.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              xmlns:tools="http://schemas.android.com/tools"
              android:layout_width="fill_parent" android:layout_height="fill_parent"
              android:orientation="vertical">

    <fragment
        android:name="com.twitpane.ui.GalleryFolderPickerFragment"
        android:id="@+id/fragment1"
        android:layout_width="wrap_content"
        android:layout_height="0dip"
        android:layout_weight="1"
        tools:layout="@layout/fragment_gallery_folder_picker" />
```

次のようにダミーのレイアウトを設定しておくことで切り替えできるようになりました。

```xml:activity_gallery_image_picker.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="fill_parent" android:layout_height="fill_parent"
              android:orientation="vertical">

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="0dip"
        android:layout_weight="1"
        android:id="@+id/mainContent"
        android:orientation="vertical"
        />
```

```java:GalleryImagePicker.java
    @Override
    public void onCreate(Bundle savedInstanceState) {
...
        //---------------------------------------
        // 初期Fragment(フォルダ一覧)表示
        //---------------------------------------
        final Fragment f = new GalleryFolderPickerFragment();
        getSupportFragmentManager().beginTransaction()
                .replace(R.id.mainContent, f)
                .commit();
    }
```

そもそもXMLに直接fragment書いてたのに切り替えできていたappcompat-21までがおかしいのかも。


# DarkActionBarテーマで ActionMode の ActionBar の背景がおかしい

[Issue 160033 - android - Wrong background in Action Mode for DarkActionBar. - Android Open Source Project - Issue Tracker - Google Project Hosting](https://code.google.com/p/android/issues/detail?id=160033)

事象は下記のスクリーンショットの通りです。

| Light テーマ(Theme.AppCompat.Light) | Dark テーマ(Theme.AppCompat) |
|-------------|-------------|
| ![2015-03-17 01.50.01s.png](https://qiita-image-store.s3.amazonaws.com/0/39221/145c3eaa-3bce-c939-9cc8-69c30ed90d5c.png) | ![2015-03-17 01.44.34s.png](https://qiita-image-store.s3.amazonaws.com/0/39221/47195d40-b347-ec5f-d59a-a567ca135235.png) |

回避方法は上記Issueにある通り、```actionModeBackground``` を任意のカラーに設定するだけです。

```xml:styles.xml

    <style name="MyAppTheme.Black" parent="Theme.AppCompat">
        <item name="actionModeBackground">@android:color/black</item>
    </style>

```

下記のほうがより自然かも。

```xml:values/styles.xml
    <style name="MyAppTheme.Black" parent="Theme.AppCompat">
        <item name="actionModeBackground">@drawable/cab_background_top_material</item>
    </style>
```

```xml:drawable/cab_background_top_material.xml
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
            android:paddingMode="stack">
    <item android:drawable="@drawable/theme_accent_background" />
    <item android:bottom="2px" android:drawable="@drawable/theme_dark_background" />
</layer-list>
```

```xml:values/colors.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <drawable name="theme_dark_background">@color/primary_material_dark</drawable>
    <drawable name="theme_accent_background">@color/accent_material_dark</drawable>
</resources>
```


| ```@android:color/black``` | ```cab_background_top_material``` |
|-------------|-------------|
| ![2015-04-05 15.17.12s.png](https://qiita-image-store.s3.amazonaws.com/0/39221/64e4a3b3-b9bd-ff1d-cd64-d3ee5794a39d.png) | ![2015-04-05 15.16.28s.png](https://qiita-image-store.s3.amazonaws.com/0/39221/c3f4189c-c3a4-aee6-006d-608a2c4c94fe.png) |



# 物理MENUキーが効かない (2015/4/2追加)

- [Issue 159795 - android - KEYCODE_MENU is broken on appcompat 22.0.0 - Android Open Source Project - Issue Tracker - Google Project Hosting](https://code.google.com/p/android/issues/detail?id=159795)
- [Issue 159703 - android - No KeyEvent.Callback.onKeyDown called, when menu key pressed after updating to support library v22.0.0 - Android Open Source Project - Issue Tracker - Google Project Hosting](https://code.google.com/p/android/issues/detail?id=159703&q=appcompat%20menu&colspec=ID%20Type%20Status%20Owner%20Summary%20Stars)

```onKeyUp```や```onKeyDown```に書いていた ```KEYCODE_MENU``` 判定処理が動作しなくなりました。

[Issue159795の#5](https://code.google.com/p/android/issues/detail?id=159795#c5)のコードにあるように ```ActionBarActivityDelegateBase``` が奪ってしまってるようです。

```onKeyUp``` がダメなら ```dispatchKeyEvent``` を使えばいいじゃない。

```java:MainActivity.java
    @Override
    public boolean onKeyUp(int keyCode, @SuppressWarnings("NullableProblems") KeyEvent event) {
        
        if (keyCode == KeyEvent.KEYCODE_MENU) {
            // メニューボタン
            showMyOptionsMenu(findViewById(R.id.menu_button));
            return true;
        }

        ...
    }
```

↓

```java:MainActivity.java
    @Override
    public boolean dispatchKeyEvent(KeyEvent event) {

        final int keyCode = event.getKeyCode();
        if (event.getAction() == KeyEvent.ACTION_UP) {

            if (keyCode == KeyEvent.KEYCODE_MENU) {
                // メニューボタン
                showMyOptionsMenu(findViewById(R.id.menu_button));
                return true;
            }
        }

        return super.dispatchKeyEvent(event);
    }
```

# レイアウトXMLに記述したボタンのpaddingが適用されない

[Issue 161359 - android - appcompat-v7 v22 XML button padding ignored - Android Open Source Project - Issue Tracker - Google Project Hosting](https://code.google.com/p/android/issues/detail?id=161359)

これは appcompat-21 から継続しているようですね。

上記 Issue にも書いてあるとおり、```inflate``` 後に ```setPadding()``` して回避しましょう。