ti.modules.titanium.ui.widget.TiUIDialog.java Source code

Java tutorial

Introduction

Here is the source code for ti.modules.titanium.ui.widget.TiUIDialog.java

Source

/**
 * Appcelerator Titanium Mobile
 * Copyright (c) 2009-2012 by Appcelerator, Inc. All Rights Reserved.
 * Licensed under the terms of the Apache Public License
 * Please see the LICENSE included with this distribution for details.
 */
package ti.modules.titanium.ui.widget;

import java.lang.ref.WeakReference;

import org.appcelerator.kroll.KrollDict;
import org.appcelerator.kroll.KrollProxy;
import org.appcelerator.kroll.common.Log;
import org.appcelerator.titanium.TiApplication;
import org.appcelerator.titanium.TiBaseActivity;
import org.appcelerator.titanium.TiBaseActivity.DialogWrapper;
import org.appcelerator.titanium.TiC;
import org.appcelerator.titanium.proxy.TiViewProxy;
import org.appcelerator.titanium.util.TiConvert;
import org.appcelerator.titanium.view.TiUIView;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.content.DialogInterface;
import android.content.DialogInterface.OnCancelListener;
import android.support.v4.view.ViewCompat;
import android.widget.ListView;

public class TiUIDialog extends TiUIView {
    private static final String TAG = "TiUIDialog";
    private static final int BUTTON_MASK = 0x10000000;

    protected Builder builder;
    protected TiUIView view;
    private DialogWrapper dialogWrapper;

    protected class ClickHandler implements DialogInterface.OnClickListener {
        private int result;

        public ClickHandler(int id) {
            this.result = id;
        }

        public void onClick(DialogInterface dialog, int which) {
            handleEvent(result);
            hide(null);
        }
    }

    public TiUIDialog(TiViewProxy proxy) {
        super(proxy);
        Log.d(TAG, "Creating a dialog", Log.DEBUG_MODE);
        createBuilder();
    }

    private Activity getCurrentActivity() {
        Activity currentActivity = TiApplication.getInstance().getCurrentActivity();
        if (currentActivity == null) {
            currentActivity = proxy.getActivity();
        }
        return currentActivity;
    }

    private Builder getBuilder() {
        if (builder == null) {
            createBuilder();
        }
        return builder;
    }

    @Override
    public void processProperties(KrollDict d) {
        String[] buttonText = null;
        if (d.containsKey(TiC.PROPERTY_TITLE)) {
            getBuilder().setTitle(d.getString(TiC.PROPERTY_TITLE));
        }
        if (d.containsKey(TiC.PROPERTY_MESSAGE)) {
            getBuilder().setMessage(d.getString(TiC.PROPERTY_MESSAGE));
        }
        if (d.containsKey(TiC.PROPERTY_BUTTON_NAMES)) {
            buttonText = d.getStringArray(TiC.PROPERTY_BUTTON_NAMES);
        } else if (d.containsKey(TiC.PROPERTY_OK)) {
            buttonText = new String[] { d.getString(TiC.PROPERTY_OK) };
        }
        if (d.containsKeyAndNotNull(TiC.PROPERTY_ANDROID_VIEW)) {
            processView((TiViewProxy) proxy.getProperty(TiC.PROPERTY_ANDROID_VIEW));
        } else if (d.containsKey(TiC.PROPERTY_OPTIONS)) {
            String[] optionText = d.getStringArray(TiC.PROPERTY_OPTIONS);
            int selectedIndex = d.containsKey(TiC.PROPERTY_SELECTED_INDEX) ? d.getInt(TiC.PROPERTY_SELECTED_INDEX)
                    : -1;
            if (selectedIndex >= optionText.length) {
                Log.d(TAG, "Ooops invalid selected index specified: " + selectedIndex, Log.DEBUG_MODE);
                selectedIndex = -1;
            }

            processOptions(optionText, selectedIndex);
        }

        if (d.containsKey(TiC.PROPERTY_PERSISTENT)) {
            dialogWrapper.setPersistent(d.getBoolean(TiC.PROPERTY_PERSISTENT));
        }

        if (buttonText != null) {
            processButtons(buttonText);
        }
        super.processProperties(d);
    }

    private void processOptions(String[] optionText, int selectedIndex) {
        getBuilder().setSingleChoiceItems(optionText, selectedIndex, new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int which) {
                handleEvent(which);
                hide(null);
            }
        });
    }

    private void processButtons(String[] buttonText) {
        getBuilder().setPositiveButton(null, null);
        getBuilder().setNegativeButton(null, null);
        getBuilder().setNeutralButton(null, null);
        getBuilder().setOnCancelListener(new OnCancelListener() {
            @Override
            public void onCancel(DialogInterface dialog) {
                dialog = null;
                if (view != null) {
                    view.getProxy().releaseViews();
                    view = null;
                }
            }
        });

        for (int id = 0; id < buttonText.length; id++) {
            String text = buttonText[id];
            ClickHandler clicker = new ClickHandler(id | BUTTON_MASK);
            switch (id) {
            case 0:
                getBuilder().setPositiveButton(text, clicker);
                break;
            case 1:
                getBuilder().setNeutralButton(text, clicker);
                break;
            case 2:
                getBuilder().setNegativeButton(text, clicker);
                break;
            default:
                Log.e(TAG, "Only 3 buttons are supported");
            }
        }
    }

    private void processView(TiViewProxy proxy) {
        if (proxy != null) {
            //reset the child view context to parent context
            proxy.setActivity(dialogWrapper.getActivity());
            view = proxy.getOrCreateView();
            getBuilder().setView(view.getNativeView());
        }
    }

    @Override
    public void propertyChanged(String key, Object oldValue, Object newValue, KrollProxy proxy) {
        Log.d(TAG, "Property: " + key + " old: " + oldValue + " new: " + newValue, Log.DEBUG_MODE);

        AlertDialog dialog = dialogWrapper.getDialog();
        if (key.equals(TiC.PROPERTY_TITLE)) {
            if (dialog != null) {
                dialog.setTitle((String) newValue);
            }
        } else if (key.equals(TiC.PROPERTY_MESSAGE)) {
            if (dialog != null) {
                dialog.setMessage((String) newValue);
            }
        } else if (key.equals(TiC.PROPERTY_BUTTON_NAMES)) {
            if (dialog != null) {
                dialog.dismiss();
                dialog = null;
            }
            processButtons(TiConvert.toStringArray((Object[]) newValue));
        } else if (key.equals(TiC.PROPERTY_OK) && !proxy.hasProperty(TiC.PROPERTY_BUTTON_NAMES)) {
            if (dialog != null) {
                dialog.dismiss();
                dialog = null;
            }
            processButtons(new String[] { TiConvert.toString(newValue) });
        } else if (key.equals(TiC.PROPERTY_OPTIONS)) {
            if (dialog != null) {
                dialog.dismiss();
                dialog = null;
            }

            getBuilder().setView(null);
            int selectedIndex = -1;
            if (proxy.hasProperty(TiC.PROPERTY_SELECTED_INDEX)) {
                selectedIndex = TiConvert.toInt(proxy.getProperty(TiC.PROPERTY_SELECTED_INDEX));
            }
            processOptions(TiConvert.toStringArray((Object[]) newValue), selectedIndex);
        } else if (key.equals(TiC.PROPERTY_SELECTED_INDEX)) {
            if (dialog != null) {
                dialog.dismiss();
                dialog = null;
            }

            getBuilder().setView(null);
            if (proxy.hasProperty(TiC.PROPERTY_OPTIONS)) {
                processOptions(TiConvert.toStringArray((Object[]) proxy.getProperty(TiC.PROPERTY_OPTIONS)),
                        TiConvert.toInt(newValue));

            }
        } else if (key.equals(TiC.PROPERTY_ANDROID_VIEW)) {
            if (dialog != null) {
                dialog.dismiss();
                dialog = null;
            }
            if (newValue != null) {
                processView((TiViewProxy) newValue);
            } else {
                proxy.setProperty(TiC.PROPERTY_ANDROID_VIEW, null);
            }
        } else if (key.equals(TiC.PROPERTY_PERSISTENT) && newValue != null) {
            dialogWrapper.setPersistent(TiConvert.toBoolean(newValue));
        } else if (key.indexOf("accessibility") == 0) {
            if (dialog != null) {
                ListView listView = dialog.getListView();
                if (listView != null) {
                    if (key.equals(TiC.PROPERTY_ACCESSIBILITY_HIDDEN)) {
                        int importance = ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_AUTO;
                        if (newValue != null && TiConvert.toBoolean(newValue)) {
                            importance = ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO;
                        }
                        ViewCompat.setImportantForAccessibility(listView, importance);
                    } else {
                        listView.setContentDescription(composeContentDescription());
                    }
                }
            }
        } else {
            super.propertyChanged(key, oldValue, newValue, proxy);
        }
    }

    public void show(KrollDict options) {
        AlertDialog dialog = dialogWrapper.getDialog();
        if (dialog == null) {
            processProperties(proxy.getProperties());
            getBuilder().setOnCancelListener(new OnCancelListener() {
                @Override
                public void onCancel(DialogInterface dlg) {
                    int cancelIndex = (proxy.hasProperty(TiC.PROPERTY_CANCEL))
                            ? TiConvert.toInt(proxy.getProperty(TiC.PROPERTY_CANCEL))
                            : -1;
                    Log.d(TAG, "onCancelListener called. Sending index: " + cancelIndex, Log.DEBUG_MODE);
                    handleEvent(cancelIndex);
                    hide(null);
                }
            });
            dialog = getBuilder().create();

            // Initially apply accessibility properties here, the first time
            // the dialog actually becomes available. After this, propertyChanged
            // can also be used.
            ListView listView = dialog.getListView();
            if (listView != null) {
                listView.setContentDescription(composeContentDescription());
                int importance = ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_AUTO;
                if (proxy != null) {
                    Object propertyValue = proxy.getProperty(TiC.PROPERTY_ACCESSIBILITY_HIDDEN);
                    if (propertyValue != null && TiConvert.toBoolean(propertyValue)) {
                        importance = ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO;
                    }
                }
                ViewCompat.setImportantForAccessibility(listView, importance);
            }

            dialogWrapper.setDialog(dialog);
            builder = null;
        }

        try {
            Activity dialogActivity = dialogWrapper.getActivity();
            if (dialogActivity != null && !dialogActivity.isFinishing()) {
                if (dialogActivity instanceof TiBaseActivity) {
                    //add dialog to its activity so we can clean it up later to prevent memory leak.
                    ((TiBaseActivity) dialogActivity).addDialog(dialogWrapper);
                    dialog.show();
                }
            } else {
                dialog = null;
                Log.w(TAG, "Dialog activity is destroyed, unable to show dialog with message: "
                        + TiConvert.toString(proxy.getProperty(TiC.PROPERTY_MESSAGE)));
            }
        } catch (Throwable t) {
            Log.w(TAG, "Context must have gone away: " + t.getMessage(), t);
        }
    }

    public void hide(KrollDict options) {
        AlertDialog dialog = dialogWrapper.getDialog();
        if (dialog != null) {
            dialog.dismiss();
            dialogWrapper.getActivity().removeDialog(dialog);
        }

        if (view != null) {
            view.getProxy().releaseViews();
            view = null;
        }
    }

    private void createBuilder() {
        Activity currentActivity = getCurrentActivity();
        if (currentActivity != null) {
            this.builder = new AlertDialog.Builder(currentActivity);
            this.builder.setCancelable(true);

            //Native dialogs are persistent by default.
            TiBaseActivity dialogActivity = (TiBaseActivity) currentActivity;
            dialogWrapper = dialogActivity.new DialogWrapper(null, true,
                    new WeakReference<TiBaseActivity>(dialogActivity));
        } else {
            Log.e(TAG, "Unable to find an activity for dialog.");
        }
    }

    public void handleEvent(int id) {
        int cancelIndex = (proxy.hasProperty(TiC.PROPERTY_CANCEL))
                ? TiConvert.toInt(proxy.getProperty(TiC.PROPERTY_CANCEL))
                : -1;
        KrollDict data = new KrollDict();
        if ((id & BUTTON_MASK) != 0) {
            data.put(TiC.PROPERTY_BUTTON, true);
            id &= ~BUTTON_MASK;
        } else {
            data.put(TiC.PROPERTY_BUTTON, false);
            // If an option was selected and the user accepted it, update the proxy.
            if (proxy.hasProperty(TiC.PROPERTY_OPTIONS)) {
                proxy.setProperty(TiC.PROPERTY_SELECTED_INDEX, id);
            }
        }
        data.put(TiC.EVENT_PROPERTY_INDEX, id);
        data.put(TiC.PROPERTY_CANCEL, id == cancelIndex);
        proxy.fireEvent(TiC.EVENT_CLICK, data);
    }
}