viernes, 30 de enero de 2015

Android: SearchView in ActionBar


res/menu/options_menu.xml
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@+id/search"
          android:title="@string/search_title"
          android:icon="@android:drawable/ic_menu_search"
          app:showAsAction="always"
          app:actionViewClass="android.support.v7.widget.SearchView" />
</menu>
Activity
public class SearchableActivity extends BaseActivity {
    
    private MenuItem searchMenuItem;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        
        super.onCreate(savedInstanceState);
        
        setContentView(R.layout.activity_searchable);

        Intent intent = getIntent();
        if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
            String query = intent.getStringExtra(SearchManager.QUERY);
            doSearch(query);
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {

        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.menu_search, menu);

        SearchView searchView = new SearchView(this);
        searchView.setOnQueryTextListener(new OnQueryTextListener() {

            @Override
            public boolean onQueryTextSubmit(String query) {
                return false;
            }

            @Override
            public boolean onQueryTextChange(String query) {
                newQuery(query);
                return false;
            }
        });
        setSearchViewTextColor(searchView);

        searchMenuItem = menu.findItem(R.id.search);
        MenuItemCompat.setShowAsAction(searchMenuItem, MenuItemCompat.SHOW_AS_ACTION_ALWAYS);
        MenuItemCompat.setActionView(searchMenuItem, searchView);

        associateSearchableConfiguration(searchMenuItem);

        return true;
    }

    private void setSearchViewTextColor(SearchView searchView) {
        for (TextView textView : findChildrenByClass(searchView, TextView.class)) {
            textView.setTextColor(Color.WHITE);
        }
    }

    private void associateSearchableConfiguration(MenuItem searchMenuItem) {

        View actionView = MenuItemCompat.getActionView(searchMenuItem);

        SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
        SearchView searchView = (SearchView) actionView;
        ComponentName componentName = new ComponentName(this, SearchableActivity.class);
        searchView.setSearchableInfo(searchManager.getSearchableInfo(componentName));
    }

    public static <V extends View> Collection<V> findChildrenByClass(ViewGroup viewGroup,
            Class<V> clazz) {

        return gatherChildrenByClass(viewGroup, clazz, new ArrayList<V>());
    }

    @SuppressWarnings("unchecked")
    private static <V extends View> Collection<V> gatherChildrenByClass(ViewGroup viewGroup,
            Class<V> clazz, Collection<V> childrenFound) {

        for (int i = 0; i < viewGroup.getChildCount(); i++)
        {
            final View child = viewGroup.getChildAt(i);
            if (clazz.isAssignableFrom(child.getClass())) {
                childrenFound.add((V) child);
            }
            if (child instanceof ViewGroup) {
                gatherChildrenByClass((ViewGroup) child, clazz, childrenFound);
            }
        }

        return childrenFound;
    }

    @Override
    protected void onNewIntent(Intent intent) {
        handleIntent(intent);
    }

    private void handleIntent(Intent intent) {

        if (Intent.ACTION_SEARCH.equals(intent.getAction())) {

            String query = intent.getStringExtra(SearchManager.QUERY);
            
            newQuery(query);
        }
    }

    protected void newQuery(String query) {
        // TODO Auto-generated method stub
    }
}


res/xml/searchable.xml
<?xml version="1.0" encoding="utf-8"?>

<searchable xmlns:android="http://schemas.android.com/apk/res/android"
        android:label="@string/app_name"
        android:hint="@string/search_hint"
         />

AndroidManifest
<activity
            android:name=".SearchableActivity"
            android:label="@string/title_activity_searchable"
            android:launchMode="singleTop" >
            <meta-data
                android:name="android.app.searchable"
                android:resource="@xml/searchable" />

            <intent-filter>
                <action android:name="android.intent.action.SEARCH" />
            </intent-filter>
        </activity>

martes, 27 de enero de 2015

Android: Navigation drawer over Action Bar

http://developer.android.com/training/basics/actionbar/overlaying.html

http://stackoverflow.com/questions/26440879/how-do-i-use-drawerlayout-to-display-over-the-actionbar-toolbar-and-under-the-st

SQL: Insert query rows into table

INSERT INTO table2
(column_name(s))
SELECT column_name(s)
FROM table1;

Example:

INSERT INTO Customers (CustomerName, Country)
SELECT SupplierName, Country FROM Suppliers;

miércoles, 21 de enero de 2015

Android: Back button using home icon on action bar

Activity
    @Override
    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        ....

        ActionBar actionBar = getSupportActionBar();
        actionBar.setDisplayUseLogoEnabled(true);
        actionBar.setHomeButtonEnabled(true);
        actionBar.setDisplayShowTitleEnabled(false);
        actionBar.setLogo(getMenuLogo());

        View v = View.inflate(this, getActionBarView(), null);
        actionBar.setDisplayShowCustomEnabled(true);
        actionBar.setCustomView(v);

        ...
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {

        switch (item.getItemId()) {

            case android.R.id.home:
                finish();
                return true;

            default:
                return super.onOptionsItemSelected(item);
        }
    }

martes, 20 de enero de 2015

Android: Date format


Date date = Calendar.getInstance().getTime();
DateFormat formatter = new SimpleDateFormat("dd/MM/yyyy hh:mm:ss");
String today = formatter.format(date);

Android ListView

Prefered sized for rows:

android:paddingStart="?android:attr/listPreferredItemPaddingStart"
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
android:minHeight="?android:attr/listPreferredItemHeight"

Android: Googleplay services


// Getting status
int status = GooglePlayServicesUtil.isGooglePlayServicesAvailable(getBaseContext());
        
// Showing status
if (status == ConnectionResult.SUCCESS) {
    // Do something on success
} else {
    // Do something on error
            
    // Show the dialog to download google play services
    int requestCode = 10;
    Dialog dialog = GooglePlayServicesUtil.getErrorDialog(status, this, requestCode);
            dialog.show();
}

jueves, 15 de enero de 2015

Android: Links inside texts


mEditText = (TextView) view.findViewById(R.id.toast_text);
            mEditText.setMovementMethod(LinkMovementMethod.getInstance());
            mEditText.setLinksClickable(true);
            Spanned text = Html.fromHtml("<html> Some text <a href=\"[url]\">Go</a> other text </html>");1
            mEditText.setText(text);
1 - If you change the text type from Spanned to String using toString(), it won't work.

Android: DialogFragment as Toast


Toast dialog class
public static class ToastDialog extends DialogFragment {

        public interface EditNameDialogListener {

            public void onDimiss();
        }

        private TextView mEditText;
        private EditNameDialogListener listener;

        public ToastDialog() {
            // Empty constructor required for DialogFragment
        }

        public static ToastDialog newInstance(String title, String text) {
            ToastDialog frag = new ToastDialog();
            Bundle args = new Bundle();
            args.putString("title", title);
            args.putString("text", text);
            frag.setArguments(args);
            return frag;
        }

        @Override
        public void onCreate(Bundle savedInstanceState) {

            super.onCreate(savedInstanceState);

            setStyle(DialogFragment.STYLE_NO_TITLE, R.style.my_dialog);
        }

        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                Bundle savedInstanceState) {
            View view = inflater.inflate(R.layout.toast_text_only, container);
            mEditText = (TextView) view.findViewById(R.id.toast_text);
            mEditText.setMovementMethod(LinkMovementMethod.getInstance());
            mEditText.setClickable(true);
            mEditText.setLinksClickable(true);
            mEditText.setText(getArguments().getString("text"));
            TextView titleText = (TextView) view.findViewById(R.id.toast_text_title);
            titleText.setText(getArguments().getString("title"));
            getDialog().setTitle(getArguments().getString("title"));
            return view;
        }

        @Override
        public void onDismiss(DialogInterface dialog) {

            super.onDismiss(dialog);

            if (listener != null) {
                listener.onDimiss();
            }
        }

        public void setListener(EditNameDialogListener listener) {
            this.listener = listener;
        }

    }
res/values/styles
<style name="my_dialog" parent="@android:style/Theme.Dialog">
        <item name="android:windowFrame">@null</item>
        <item name="android:windowBackground">@android:color/transparent</item>
        <item name="android:windowIsFloating">true</item>
        <item name="android:windowContentOverlay">@null</item>
        <item name="android:windowTitleStyle">@null</item>
        <item name="android:colorBackgroundCacheHint">@null</item>
        <item name="android:windowAnimationStyle">@android:style/Animation.Dialog</item>
        <item name="android:windowSoftInputMode">stateUnspecified|adjustPan</item>
        <item name="android:gravity">center</item>
    </style>
User
FragmentManager fm = activity.getSupportFragmentManager();
        ToastDialog editNameDialog = ToastDialog.newInstance(title, text);
        editNameDialog.show(fm, "fragment_toast");
res/layout
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     android:background="#C8000000"
     android:orientation="vertical">
     
 <TextView 
     android:id="@+id/toast_text_title"
     android:layout_width="wrap_content"
     android:minHeight="40dp"
     android:layout_height="wrap_content"
     android:textColor="#762b76"
     android:layout_marginBottom="10dp"
     android:layout_marginTop="10dp"
        android:paddingLeft="40dp"
     android:paddingRight="40dp"  
     android:textSize="22sp" />    

 <LinearLayout 
     android:layout_width="fill_parent"
     android:layout_height="1dp"
        android:layout_marginLeft="20dp"
     android:layout_marginRight="20dp" 
     android:background="@color/text_color_1" />
      
 <TextView 
     android:id="@+id/toast_text"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     android:paddingTop="10dp" 
        android:paddingLeft="40dp"
     android:paddingRight="40dp" 
     android:textColor="@color/text_color_1"
     android:textSize="20sp"
     android:lineSpacingMultiplier="1.3"
     android:layout_marginBottom="10dp"
     android:layout_gravity="center_vertical" />
 
</LinearLayout>

lunes, 5 de enero de 2015

Android: Testing notifications easely

Para probar notificaciones rapidamente, sin hacer un seteo de un servidor y su configuracion (rapido en dev):

2- Configurar ApiKey (Server key, desde API console) y SenderId (project id desde API Console)
3- Completar el titulo y mensaje, y darle al boton "Send GCM..."

Desde la app, para registrar el token:

private void sendRegistrationIdToBackend() {
String url = "http://gcm4public.appspot.com/registergcmclient?senderId=" + SENDER_ID + "&registrationId=" + regid;
    DefaultHttpClient httpclient = new DefaultHttpClient();
    HttpGet httpget = new HttpGet(url);
    try {
        httpclient.execute(httpget);
    } catch (ClientProtocolException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

Android: Libraries

https://github.com/snowdream/awesome-android

Persistance frameworks
Active Android

Image loading frameworks
Universal Image Loader