2015-05-09

Living in the past (Teil 2)

In meinem vorherigen Post habe ich angedeutet, dass man unter neueren Android-Versionen Live Folder noch nutzen kann, obwohl Google die korrespondierenden Klassen mit API-Level 14 für veraltet erklärt und den Zugriff über den Home Screen ausgebaut hat.

Das Installieren einer App, die Live Folder bereitstellt, klappt selbst unter Android 5.1 noch reibungslos. Die beteiligten Frameworksklassen sind also (zum Glück) noch vorhanden. Eigentlich ist das auch logisch, denn das harte Entfernen hielte ich schon für einen ziemlich signifikanten Einschnitt. Über den Home Screen ist das Hinzufügen von Live Foldern aber nicht mehr möglich. Die Frage ist also, wie man Zugriff erhält. Hierzu muss man wissen, dass Live Folder keine Benutzeroberfläche bereitstellen, sondern nur die Daten, und zwar in Gestalt eines (auf eine ganz bestimmte Weise konfektionierten) Content Providers.

Die Idee ist deshalb, selbst für die UI zu sorgen, und den Content Provider einfach nach seinen Daten zu fragen. Die folgende Activity zeigt einen entsprechenden Proof of Concept, den ich Tin Opener genannt habe. Ich werde die App in den nächsten Tagen auf Bitbucket bereitstellen. Wenn das erledigt ist, füge ich diesem Post einfach einen Kommentar hinzu.

public class TinOpenerActivity extends ListActivity 
    implements LoaderManager.LoaderCallbacks<Cursor> {

    private static final String TAG = 
            TinOpenerActivity.class.getSimpleName();
    private static final int RQ_PICK_LIVE_FOLDER = 42;
    private static final int URL_LOADER = 0;

    private Uri uri;
    private String[] mFromColumns = {
            LiveFolders.NAME, LiveFolders.DESCRIPTION
    };
    private int[] mToFields = {
            android.R.id.text1, android.R.id.text2
    };
    private SimpleCursorAdapter adapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setListAdapter(adapter = new SimpleCursorAdapter(this, 
                android.R.layout.simple_list_item_2, null, 
                mFromColumns, mToFields, 0));
        getListView().setOnItemClickListener(
            new AdapterView.OnItemClickListener() {

            @Override
            public void onItemClick(AdapterView<?> parent, 
                                    View view, int position, 
                                    long id) {
                Cursor c = (Cursor) adapter.getItem(position);
                if (c != null) {
                    String url = c.getString(
                        c.getColumnIndex(LiveFolders.INTENT));
                    if (url != null) {
                        Intent i = new Intent(Intent.ACTION_VIEW);
                        i.setData(Uri.parse(url));
                        startActivity(i);
                    }
                }
            }
        });
        Intent i = new Intent(LiveFolders.ACTION_CREATE_LIVE_FOLDER);
        Intent chooser = Intent.createChooser(i, 
                getString(R.string.choose));
        startActivityForResult(chooser, RQ_PICK_LIVE_FOLDER);
    }

    @Override
    protected void onActivityResult(int requestCode, 
                                    int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if ((RESULT_OK == resultCode) && 
                (RQ_PICK_LIVE_FOLDER == requestCode)) {
            if (data != null) {
                uri = data.getData();
                if (uri != null) {
                    getLoaderManager().initLoader(URL_LOADER, 
                            null, this);
                }
            }
        }
    }

    @Override
    public Loader<Cursor> onCreateLoader(int loaderID, 
                                         Bundle args) {
        switch (loaderID) {
            case URL_LOADER:
                return new CursorLoader(this, uri, 
                        null, null, null, null);
            default:
                return null;
        }
    }

    @Override
    public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
        adapter.changeCursor(data);
    }

    @Override
    public void onLoaderReset(Loader<Cursor> loader) {
    }
}

Die App TinOpener ist sehr einfach gestrickt. Sie besteht aus einer ListActivity, die ihre Daten von einem SimpleCursorAdapter bezieht. So wie sich das gehört, geschieht das Laden mit Hilfe eines Loaders im Hintergrund.

Die eigentlich spannende Frage ist, wie Live Folder gefunden werden. Hierfür baue ich ein Intent mit der Action LiveFolders.ACTION_CREATE_LIVE_FOLDER und lasse es auf die systemeigene Intent-Auswahl los. Sind mehrere Live Folder installiert, kann der Benutzer einen auswählen. Ist nur einer vorhanden, wird dieser automatisch angezeigt.

Statt in eine Activity könnte man dies auch in ein Appwidget packen. Na, hat jemand Lust darauf?

Nachtrag: Ja, das Listing enthält keine Kommentare... Ich werde dies in der Version auf Bitbucket nachholen. Und den Fall berücksichtigen, dass gar kein Live Folder vorhanden ist. Dann sollte zumindest ein entsprechender Hinweis erfolgen.

1 comment:

  1. Wie versprochen, habe ich das Projekt TinOpener auf Bitbucket hochgeladen. Sie finden es im Repository Outtakes.

    ReplyDelete