/* ******************************************************************************** * Copyright (c) 2012 Samsung Electronics, Inc. * All rights reserved. * * This software is a confidential and proprietary information of Samsung * Electronics, Inc. ("Confidential Information"). You shall not disclose such * Confidential Information and shall use it only in accordance with the terms * of the license agreement you entered into with Samsung Electronics. ******************************************************************************** */ package com.sprc.circlelauncher; import android.app.ActionBar; import android.app.Activity; import android.app.FragmentManager; import android.app.FragmentTransaction; import android.content.ClipData; import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.ResolveInfo; import android.os.Bundle; import android.os.Debug; import android.preference.PreferenceManager; import android.util.Log; import android.view.DragEvent; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.View.DragShadowBuilder; import android.view.View.OnClickListener; import android.view.View.OnDragListener; import android.view.Window; import android.widget.Adapter; import android.widget.BaseAdapter; import com.sprc.circlelauncher.PackageAdapter.OnCircleItemClickListener; import com.sprc.circlelauncher.PackageAdapter.OnCircleItemHoverButtonListener; import com.sprc.circlelauncher.PackageAdapter.OnCircleItemHoverListener; import com.sprc.circlelauncher.PackageAdapter.OnCircleItemLongClickListener; import com.sprc.circlelauncher.popup.AppPopupWindow; import com.sprc.circlelauncher.view.CircleListView; import com.sprc.circlelauncher.view.CircleListView.OnItemCenteredListener; import com.sprc.circlelauncher.view.CircularViewModifier; /** * Provides a drawer of applications in a wheel form. * * @author sprc * */ public class LauncherActivity extends Activity implements OnCircleItemClickListener, OnCircleItemLongClickListener, OnCircleItemHoverListener, OnCircleItemHoverButtonListener, OnDragListener, OnClickListener, OnItemCenteredListener { private static final boolean DEBUG = BuildConfig.DEBUG && false; private static final String TAG = LauncherActivity.class.getSimpleName(); private static final int MENU_ITEM_CHOSE_APP = 1001; private static final int MENU_ITEM_HELP = 1002; public static final int REQUEST_CODE_UNINSTALL = 1; private static final String DRAG_LABEL_SHORTCUT = "Dragging shortcut"; private static final long HOVER_TIME_TRIGGER = 500; private static final String SP_KEY_IS_FIRST_RUN = "isFirstRun"; private CircleListView mCircleListView; private PackageAdapter mPackageAdapter; private AppDetailsFragment mAppDetailsFragment; private int mLastPosition; private long mHoverStartTime; private AppPopupWindow mCircleAppContextMenu; @Override public void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (getWindow() != null) { getWindow().requestFeature(Window.FEATURE_ACTION_BAR_OVERLAY); } setContentView(R.layout.activity_launcher); if (DEBUG) { Debug.waitForDebugger(); } mCircleListView = (CircleListView) findViewById(R.id.circle_list); mPackageAdapter = new PackageAdapter(this); // Set CircleListView's item listeners mPackageAdapter.setOnCircleItemClickListener(this); mPackageAdapter.setOnCircleItemLongClickListener(this); mPackageAdapter.setOnCircleItemHoverListener(this); mPackageAdapter.setOnCircleItemHoverButtonDownListener(this); ((View) mCircleListView.getParent()).setOnClickListener(this); mCircleListView.setAdapter(mPackageAdapter); mCircleListView.setViewModifier(new CircularViewModifier()); CircleListView v = (CircleListView) findViewById(R.id.circle_list); v.setOnDragListener(this); v.setOnItemCenteredListener(this); mCircleAppContextMenu = new AppPopupWindow(this); ActionBar actionBar = getActionBar(); if (actionBar != null) { actionBar.setDisplayShowTitleEnabled(false); actionBar.setDisplayShowHomeEnabled(false); actionBar.setBackgroundDrawable(null); } if (isFirstLaunch()) { SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); SharedPreferences.Editor editor = prefs.edit(); editor.putBoolean(SP_KEY_IS_FIRST_RUN, false); editor.commit(); showHelpDialog(); } } /** * Checks if this is the first launch of this application. * * @return true if the application was not run before, false otherwise */ private boolean isFirstLaunch() { SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); return prefs.getBoolean(SP_KEY_IS_FIRST_RUN, true); } @Override public boolean onCreateOptionsMenu(final Menu menu) { menu.add(0, MENU_ITEM_CHOSE_APP, 1, R.string.menu_title_chooseapps); menu.add(0, MENU_ITEM_HELP, 2, R.string.menu_title_help); return super.onCreateOptionsMenu(menu); } @Override protected void onResume() { super.onResume(); mPackageAdapter.reloadApplications(); } @Override public boolean onOptionsItemSelected(final MenuItem item) { switch (item.getItemId()) { case MENU_ITEM_CHOSE_APP: { final Intent myIntent = new Intent(this, ChooseAppsActivity.class); startActivity(myIntent); break; } case MENU_ITEM_HELP: { showHelpDialog(); break; } } return super.onOptionsItemSelected(item); } @Override protected void onActivityResult(final int requestCode, final int resultCode, final Intent data) { switch (requestCode) { case REQUEST_CODE_UNINSTALL: mPackageAdapter.reloadApplications(); break; default: break; } super.onActivityResult(requestCode, resultCode, data); } public boolean onDrag(final View v, final DragEvent event) { switch (event.getAction()) { case DragEvent.ACTION_DRAG_STARTED: if (DEBUG) { Log.d(TAG, "ACTION_DRAG_STARTED"); } return true; case DragEvent.ACTION_DRAG_EXITED: if (DEBUG) { Log.d(TAG, "ACTION_DRAG_EXITED"); } // Exited the CircleListView, close the Launcher and show Home. finish(); break; default: break; } return false; } /** * {@link OnCircleItemClickListener#onClick(View, BaseAdapter)} implementation for the circle list. */ public void onClick(final View v, final BaseAdapter adapter) { final int position = (Integer) v.getTag(R.id.key_position); final ResolveInfo info = (ResolveInfo) mPackageAdapter.getItem(position); if (v.equals(mCircleListView.findViewAtCenter())) { if (info != null) { final Intent intent = getPackageManager().getLaunchIntentForPackage(info.activityInfo.packageName); startActivity(intent); } } else { mCircleListView.smoothScrollToView(v); showAppDetails(info); } } /** * Handles the long click on the middle {@link View} in the {@link #mCircleListView}. */ public boolean onLongClick(final View v, final BaseAdapter adapter) { // Start dragging the application icon. final int position = (Integer) v.getTag(R.id.key_position); final ResolveInfo info = (ResolveInfo) adapter.getItem(position); if (info != null) { final View iconView = v.findViewById(R.id.icon); final ClipData data = ClipData.newPlainText(DRAG_LABEL_SHORTCUT, "Dragging: " + info.resolvePackageName); iconView.startDrag(data, new DragShadowBuilder(iconView), v, 0); return true; } return false; } /** * Handles the hover event on the {@link View} in the {@link #mCircleListView}. */ public boolean onHover(final View v, final BaseAdapter adapter, long eventTime) { if (DEBUG) { Log.d(TAG, "onHover()"); } if (isFinishing()) { return true; } final int position = (Integer) v.getTag(R.id.key_position); final ResolveInfo info = getResolveInfo(v, adapter); if (position == mLastPosition) { // Still hovering over the same item if (eventTime - mHoverStartTime > HOVER_TIME_TRIGGER) { showAppDetails(info); } } else { // Hovering over a new item mHoverStartTime = eventTime; mLastPosition = position; } return true; } public boolean onHoverButtonDown(final View v, final BaseAdapter adapter, long eventTime) { if (DEBUG) { Log.d(TAG, "onHoverButtonDown"); } final ResolveInfo info = getResolveInfo(v, adapter); mCircleAppContextMenu.setResolveInfo(info); mCircleAppContextMenu.setAnchor(v); mCircleAppContextMenu.showMenu(); return true; } public boolean onHoverButtonUp(final View v, final BaseAdapter adapter, long eventTime) { return false; } public void onClick(final View v) { showAppDetails(null); } public void onItemCentered(View v) { if (v != null) { final int position = (Integer) v.getTag(R.id.key_position); final ResolveInfo info = (ResolveInfo) mPackageAdapter.getItem(position); showAppDetails(info); } } /** * Shows an {@link AppDetailsFragment} with application info. * * @param info * the {@link ResolveInfo} object with information of an application suitable to launch */ private void showAppDetails(final ResolveInfo info) { if (info != null) { if (mAppDetailsFragment != null && info.equals(mAppDetailsFragment.getResolveInfo())) { return; } mAppDetailsFragment = AppDetailsFragment.newInstance(info); final FragmentManager fm = getFragmentManager(); final FragmentTransaction ft = fm.beginTransaction(); ft.setCustomAnimations(android.R.animator.fade_in, android.R.animator.fade_out); ft.replace(R.id.placeholder_appdetails, mAppDetailsFragment); ft.commit(); } else if (mAppDetailsFragment != null) { final FragmentManager fm = getFragmentManager(); final FragmentTransaction ft = fm.beginTransaction(); ft.remove(mAppDetailsFragment); ft.setCustomAnimations(android.R.animator.fade_in, android.R.animator.fade_out); ft.commit(); mAppDetailsFragment = null; } else { finish(); } } private void showHelpDialog() { FragmentTransaction ft = getFragmentManager().beginTransaction(); HelpDialogFragment frag = HelpDialogFragment.newInstance(); frag.show(ft, null); } /** * A helper method to retrieve a {@link ResolveInfo} object from the {@link Adapter}. * * @param v * a {@link View} that contains a key with the position in the {@link Adapter} * @param adapter * actual {@link Adapter} * @return the {@link ResolveInfo} object */ private static ResolveInfo getResolveInfo(final View v, final BaseAdapter adapter) { final int position = (Integer) v.getTag(R.id.key_position); return (ResolveInfo) adapter.getItem(position); } }