OmniGears: [2/3] Customizable lockscreen & navring targets

Original commit:

Navigation ring customization
Autor: Danny Baumann <dannybaumann@web.de>  2013-11-18 09:07:48
Change-Id: Iec29417ab65efc8df593508204b0981d5b193b74
diff --git a/res/drawable-hdpi/ic_empty.png b/res/drawable-hdpi/ic_empty.png
new file mode 100644
index 0000000..a45c6cf
--- /dev/null
+++ b/res/drawable-hdpi/ic_empty.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_navigation_ring_hint.png b/res/drawable-hdpi/ic_navigation_ring_hint.png
new file mode 100644
index 0000000..116b1f0
--- /dev/null
+++ b/res/drawable-hdpi/ic_navigation_ring_hint.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_empty.png b/res/drawable-mdpi/ic_empty.png
new file mode 100644
index 0000000..ede2c83
--- /dev/null
+++ b/res/drawable-mdpi/ic_empty.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_navigation_ring_hint.png b/res/drawable-mdpi/ic_navigation_ring_hint.png
new file mode 100644
index 0000000..7a70984
--- /dev/null
+++ b/res/drawable-mdpi/ic_navigation_ring_hint.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_empty.png b/res/drawable-xhdpi/ic_empty.png
new file mode 100644
index 0000000..5742d13
--- /dev/null
+++ b/res/drawable-xhdpi/ic_empty.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_navigation_ring_hint.png b/res/drawable-xhdpi/ic_navigation_ring_hint.png
new file mode 100644
index 0000000..e2aed09
--- /dev/null
+++ b/res/drawable-xhdpi/ic_navigation_ring_hint.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_navigation_ring_hint.png b/res/drawable-xxhdpi/ic_navigation_ring_hint.png
new file mode 100644
index 0000000..e5ef85d
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_navigation_ring_hint.png
Binary files differ
diff --git a/res/values/custom_arrays.xml b/res/values/custom_arrays.xml
index c673416..62e464b 100644
--- a/res/values/custom_arrays.xml
+++ b/res/values/custom_arrays.xml
@@ -220,4 +220,56 @@
         <item>2</item>
     </string-array>
 
+    <string-array name="lockscreen_icon_picker_labels" translatable="false">
+        <item>@string/icon_picker_alarm</item>
+        <item>@string/icon_picker_browser</item>
+        <item>@string/icon_picker_calendar</item>
+        <item>@string/icon_picker_camera</item>
+        <item>@string/icon_picker_chrome</item>
+        <item>@string/icon_picker_contacts</item>
+        <item>@string/icon_picker_email</item>
+        <item>@string/icon_picker_email2</item>
+        <item>@string/icon_picker_facebook</item>
+        <item>@string/icon_picker_gallery</item>
+        <item>@string/icon_picker_google_small</item>
+        <item>@string/icon_picker_googleplus</item>
+        <item>@string/icon_picker_googletalk</item>
+        <item>@string/icon_picker_maps</item>
+        <item>@string/icon_picker_sms</item>
+        <item>@string/icon_picker_movie</item>
+        <item>@string/icon_picker_music</item>
+        <item>@string/icon_picker_nav_normal</item>
+        <item>@string/icon_picker_phone</item>
+        <item>@string/icon_picker_podcast</item>
+        <item>@string/icon_picker_rss</item>
+        <item>@string/icon_picker_search</item>
+        <item>@string/icon_picker_twitter</item>
+    </string-array>
+
+    <string-array name="lockscreen_icon_picker_icons" translatable="false">
+        <item>ic_lockscreen_alarm_normal</item>
+        <item>ic_lockscreen_browser_normal</item>
+        <item>ic_lockscreen_calendar_normal</item>
+        <item>ic_lockscreen_camera_normal</item>
+        <item>ic_lockscreen_chrome_normal</item>
+        <item>ic_lockscreen_contacts_normal</item>
+        <item>ic_lockscreen_email_normal</item>
+        <item>ic_lockscreen_email2_normal</item>
+        <item>ic_lockscreen_facebook_normal</item>
+        <item>ic_lockscreen_gallery_normal</item>
+        <item>ic_lockscreen_google_small_normal</item>
+        <item>ic_lockscreen_gplus_normal</item>
+        <item>ic_lockscreen_gtalk_normal</item>
+        <item>ic_lockscreen_maps_normal</item>
+        <item>ic_lockscreen_sms_normal</item>
+        <item>ic_lockscreen_movie_normal</item>
+        <item>ic_lockscreen_music_normal</item>
+        <item>ic_lockscreen_nav_normal</item>
+        <item>ic_lockscreen_phone_normal</item>
+        <item>ic_lockscreen_podcast_normal</item>
+        <item>ic_lockscreen_rss_normal</item>
+        <item>ic_lockscreen_google_normal</item>
+        <item>ic_lockscreen_twitter_normal</item>
+    </string-array>
+
 </resources>
diff --git a/res/values/custom_strings.xml b/res/values/custom_strings.xml
index a830544..85df0dd 100644
--- a/res/values/custom_strings.xml
+++ b/res/values/custom_strings.xml
@@ -24,6 +24,7 @@
     <string name="bars_and_menus_settings">Bars and menus</string>
     <string name="active_display_settings">ActiveDisplay</string>
     <string name="bars_and_menus_category_status_bar_title">Status bar</string>
+    <string name="bars_and_menus_category_navigation_bar_title">Navigation bar</string>
     <string name="status_bar_battery_title">Battery style</string>
     <string name="status_bar_toggle_brightness">Brightness control</string>
     <string name="status_bar_toggle_brightness_summary">Adjust brightness by sliding across status bar</string>
@@ -297,4 +298,66 @@
     <string name="button_volume_default_title">Volume default</string>
     <string name="button_volume_default_summary">Choose which volume gets changed by default</string>
 
+    <!-- Navigation ring shortcuts -->
+    <string name="navigation_ring_title">Quick launch shortcuts</string>
+    <string name="navring_target_reset_message">Delete all user created navigation bar shortcuts and restore to default?</string>
+    <string name="navring_target_reset">Navigation bar shortcuts reset to default</string>
+    <string name="navring_action_open_ime_switcher">Open IME Switcher</string>
+    <string name="navring_action_kill_app">Kill app</string>
+    <string name="navring_action_none">None</string>
+    <string name="navring_action_take_screenshot">Take screenshot</string>
+    <string name="navring_action_ring_vibrate">Ring/Vibration</string>
+    <string name="navring_action_ring_silent">Ring/Silent</string>
+    <string name="navring_action_ring_vibrate_silent">Ring/Vibration/Silent</string>
+    <string name="navring_action_screen_off">Screen off</string>
+    <string name="navring_action_torch">Toggle torch</string>
+    <string name="navring_action_google_now">Google Now</string>
+    <string name="navring_choose_action_title">Choose action</string>
+
+    <!-- String for IconPicker -->
+    <string name="icon_picker_title">Choose icon source</string>
+    <string name="icon_picker_system_icons_title">System icons</string>
+    <string name="icon_picker_gallery_title">Gallery</string>
+    <string name="icon_picker_pack_title">Icon pack</string>
+
+    <!-- Lock Screen Shortcuts -->
+    <string name="lockscreen_target_info">Drag the slider to targets to assign shortcuts</string>
+    <string name="lockscreen_target_title">Slider shortcuts</string>
+    <string name="lockscreen_target_summary">View or change custom lock screen shortcuts</string>
+    <string name="lockscreen_target_reset">Lock screen shortcuts reset to default</string>
+    <string name="lockscreen_target_reset_title">Reset</string>
+    <string name="lockscreen_target_reset_message">Delete all user created lock screen shortcuts and restore to default?</string>
+    <string name="lockscreen_target_empty">Empty</string>
+    <string name="lockscreen_target_edit_title">Edit shortcut and icon</string>
+    <string name="lockscreen_target_edit_msg">Select or change the desired application or activity and the associated icon</string>
+
+    <!-- Lock screen shortcuts -->
+    <string name="picker_activities">Activities</string>
+    <string name="select_custom_app_title">Select custom app</string>
+    <string name="select_custom_activity_title">Select custom activity</string>
+    <string name="icon_picker_choose_icon_title">Choose icon</string>
+    <string name="icon_picker_alarm">Alarm</string>
+    <string name="icon_picker_browser">Browser</string>
+    <string name="icon_picker_calendar">Calendar</string>
+    <string name="icon_picker_camera">Camera</string>
+    <string name="icon_picker_chrome">Chrome</string>
+    <string name="icon_picker_contacts">Contacts</string>
+    <string name="icon_picker_email">Email</string>
+    <string name="icon_picker_email2">Email Holo</string>
+    <string name="icon_picker_facebook">Facebook</string>
+    <string name="icon_picker_gallery">Gallery</string>
+    <string name="icon_picker_google_small">Google (small)</string>
+    <string name="icon_picker_googleplus">Google Plus</string>
+    <string name="icon_picker_googletalk">Hangouts</string>
+    <string name="icon_picker_maps">Maps</string>
+    <string name="icon_picker_movie">Movie</string>
+    <string name="icon_picker_music">Music</string>
+    <string name="icon_picker_nav_normal">Navigation</string>
+    <string name="icon_picker_phone">Phone</string>
+    <string name="icon_picker_podcast">Podcast</string>
+    <string name="icon_picker_rss">Rss</string>
+    <string name="icon_picker_search">Search</string>
+    <string name="icon_picker_sms">Messaging</string>
+    <string name="icon_picker_twitter">Twitter</string>
+
 </resources>
diff --git a/res/xml/bars_settings.xml b/res/xml/bars_settings.xml
index 14ec555..ec06255 100644
--- a/res/xml/bars_settings.xml
+++ b/res/xml/bars_settings.xml
@@ -49,4 +49,14 @@
             android:summary="@string/show_activity_indicators_on_status_bar_summary"
             android:defaultValue="false" />
 
+    <!-- Navigation bar -->
+    <PreferenceCategory
+            android:key="category_navigation_bar"
+            android:title="@string/bars_and_menus_category_navigation_bar_title"/>
+
+    <PreferenceScreen
+        android:key="navigation_ring"
+        android:fragment="org.omnirom.omnigears.interfacesettings.NavRing"
+        android:title="@string/navigation_ring_title" />
+
 </PreferenceScreen>
diff --git a/src/org/omnirom/omnigears/interfacesettings/BarsSettings.java b/src/org/omnirom/omnigears/interfacesettings/BarsSettings.java
index 63b140e..95c9a79 100644
--- a/src/org/omnirom/omnigears/interfacesettings/BarsSettings.java
+++ b/src/org/omnirom/omnigears/interfacesettings/BarsSettings.java
@@ -24,6 +24,7 @@
 import android.content.ContentResolver;
 import android.content.Context;
 import android.os.Bundle;
+import android.os.RemoteException;
 import android.preference.CheckBoxPreference;
 import android.preference.Preference;
 import android.preference.PreferenceGroup;
@@ -31,6 +32,7 @@
 import android.provider.Settings;
 import android.provider.Settings.SettingNotFoundException;
 import android.util.Log;
+import android.view.WindowManagerGlobal;
 
 public class BarsSettings extends SettingsPreferenceFragment implements
         Preference.OnPreferenceChangeListener {
@@ -41,6 +43,8 @@
     private static final String STATUS_BAR_TRAFFIC = "status_bar_traffic";
     private static final String STATUS_BAR_NETWORK_ACTIVITY = "status_bar_network_activity";
 
+    private static final String CATEGORY_NAVBAR = "category_navigation_bar";
+
     private CheckBoxPreference mStatusBarBrightnessControl;
     private CheckBoxPreference mStatusBarNotifCount;
     private CheckBoxPreference mStatusBarTraffic;
@@ -82,11 +86,22 @@
             Settings.System.STATUS_BAR_NETWORK_ACTIVITY, 0) == 1);
         mStatusBarNetworkActivity.setOnPreferenceChangeListener(this);
         mStatusBarNetworkActivity.setOnPreferenceChangeListener(this);
+
+        try {
+            boolean hasNavBar = WindowManagerGlobal.getWindowManagerService().hasNavigationBar();
+            // Hide navigation bar category on devices without navigation bar
+            if (!hasNavBar) {
+                prefSet.removePreference(findPreference(CATEGORY_NAVBAR));
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error getting navigation bar status");
+        }
     }
 
     @Override
     public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
-        return true;
+        // If we didn't handle it, let preferences handle it.
+        return super.onPreferenceTreeClick(preferenceScreen, preference);
     }
 
     public boolean onPreferenceChange(Preference preference, Object objValue) {
@@ -108,7 +123,6 @@
         } else {
             return false;
         }
-
         return true;
     }
 }
diff --git a/src/org/omnirom/omnigears/interfacesettings/IconPicker.java b/src/org/omnirom/omnigears/interfacesettings/IconPicker.java
new file mode 100644
index 0000000..a43222e
--- /dev/null
+++ b/src/org/omnirom/omnigears/interfacesettings/IconPicker.java
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2012 The CyanogenMod Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.omnirom.omnigears.interfacesettings;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.Fragment;
+import android.content.ActivityNotFoundException;
+import android.content.ComponentName;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.graphics.Bitmap;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.provider.MediaStore;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.AdapterView.OnItemClickListener;
+import android.widget.BaseAdapter;
+import android.widget.ListView;
+import android.widget.TextView;
+
+import com.android.internal.util.cm.LockscreenTargetUtils;
+import com.android.settings.R;
+
+import java.io.File;
+
+public class IconPicker {
+    private static final String ICON_ACTION = "com.cyanogenmod.ACTION_PICK_ICON";
+    public static final String RESOURCE_NAME = "resource_name";
+    public static final String PACKAGE_NAME = "package_name";
+
+    public static final int REQUEST_PICK_SYSTEM = 0;
+    public static final int REQUEST_PICK_GALLERY = 1;
+    public static final int REQUEST_PICK_ICON_PACK = 2;
+
+    private Activity mParent;
+    private Resources mResources;
+    private OnIconPickListener mIconListener;
+
+    public interface OnIconPickListener {
+        void iconPicked(int requestCode, int resultCode, Intent in);
+    }
+
+    public IconPicker(Activity parent, OnIconPickListener listener) {
+        mParent = parent;
+        mResources = parent.getResources();
+        mIconListener = listener;
+    }
+
+    public void onActivityResult(int requestCode, int resultCode, Intent data) {
+        mIconListener.iconPicked(requestCode, resultCode, data);
+    }
+
+    public void pickIcon(final int fragmentId, final File image) {
+        Intent iconPackIntent = new Intent(ICON_ACTION);
+        ComponentName component = iconPackIntent.resolveActivity(mParent.getPackageManager());
+
+        String[] items = new String[component != null ? 2 : 1];
+        items[0] = mResources.getString(R.string.icon_picker_system_icons_title);
+        //items[1] = mResources.getString(R.string.icon_picker_gallery_title);
+        if (component != null) {
+            items[1] = mResources.getString(R.string.icon_picker_pack_title);
+        }
+
+        new AlertDialog.Builder(mParent)
+                .setTitle(R.string.icon_picker_title)
+                .setItems(items, new DialogInterface.OnClickListener() {
+                    @Override
+                    public void onClick(DialogInterface dialog, int item) {
+                        showChosen(item, image, fragmentId);
+                    }
+                })
+                .show();
+    }
+
+    private void startFragmentOrActivityForResult(Intent pickIntent,
+            int requestCode, int fragmentId) {
+        if (fragmentId == 0) {
+            mParent.startActivityForResult(pickIntent, requestCode);
+        } else {
+            Fragment fragment = mParent.getFragmentManager().findFragmentById(fragmentId);
+            if (fragment != null) {
+                mParent.startActivityFromFragment(fragment, pickIntent, requestCode);
+            }
+        }
+    }
+
+    private void showChosen(final int type, File image, int fragmentId) {
+        if (type == REQUEST_PICK_SYSTEM) {
+            ListView list = new ListView(mParent);
+            final IconAdapter adapter = new IconAdapter();
+
+            final Dialog dialog = new Dialog(mParent);
+            dialog.setTitle(R.string.icon_picker_choose_icon_title);
+            dialog.setContentView(list);
+
+            list.setAdapter(adapter);
+            list.setOnItemClickListener(new OnItemClickListener(){
+                @Override
+                public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+                    Intent intent = new Intent();
+                    intent.putExtra(RESOURCE_NAME, adapter.getItemReference(position));
+                    mIconListener.iconPicked(type, Activity.RESULT_OK, intent);
+                    dialog.dismiss();
+                }
+            });
+            dialog.show();
+        } else if (type == REQUEST_PICK_GALLERY) {
+            Intent intent = new Intent(Intent.ACTION_GET_CONTENT, null);
+            intent.setType("image/*");
+            intent.putExtra("crop", "true");
+            intent.putExtra("scale", true);
+            intent.putExtra("scaleUpIfNeeded", false);
+            intent.putExtra("outputFormat", Bitmap.CompressFormat.PNG.toString());
+            intent.putExtra("aspectX", 1);
+            intent.putExtra("aspectY", 1);
+            intent.putExtra("outputX", 162);
+            intent.putExtra("outputY", 162);
+            try {
+                intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(image));
+                intent.putExtra("return-data", false);
+                startFragmentOrActivityForResult(intent, type, fragmentId);
+            } catch (ActivityNotFoundException e) {
+                e.printStackTrace();
+            }
+        } else if (type == REQUEST_PICK_ICON_PACK) {
+            Intent iconPackIntent = new Intent(ICON_ACTION);
+            startFragmentOrActivityForResult(iconPackIntent, type, fragmentId);
+        }
+    }
+
+    class IconAdapter extends BaseAdapter {
+        String[] labels;
+        String[] icons;
+
+        public IconAdapter() {
+            labels = mResources.getStringArray(R.array.lockscreen_icon_picker_labels);
+            icons = mResources.getStringArray(R.array.lockscreen_icon_picker_icons);
+        }
+
+        @Override
+        public int getCount() {
+            return labels.length;
+        }
+
+        @Override
+        public Object getItem(int position) {
+            return LockscreenTargetUtils.getDrawableFromResources(
+                    mParent, null, icons[position], false);
+        }
+
+        public String getItemReference(int position) {
+            String name = icons[position];
+            return name;
+        }
+
+        @Override
+        public long getItemId(int position) {
+            return 0;
+        }
+
+        @Override
+        public View getView(int position, View convertView, ViewGroup parent) {
+            View view = convertView;
+            if (convertView == null) {
+                view = View.inflate(mParent, android.R.layout.simple_list_item_1, null);
+            }
+
+            TextView label = (TextView) view.findViewById(android.R.id.text1);
+            label.setText(labels[position]);
+
+            Drawable icon = ((Drawable) getItem(position)).mutate();
+            int bound = mParent.getResources().getDimensionPixelSize(
+                    R.dimen.shortcut_picker_left_padding);
+
+            icon.setBounds(0,  0, bound, bound);
+            label.setCompoundDrawables(icon, null, null, null);
+
+            return view;
+        }
+    }
+}
diff --git a/src/org/omnirom/omnigears/interfacesettings/LockscreenTargets.java b/src/org/omnirom/omnigears/interfacesettings/LockscreenTargets.java
new file mode 100644
index 0000000..40c593b
--- /dev/null
+++ b/src/org/omnirom/omnigears/interfacesettings/LockscreenTargets.java
@@ -0,0 +1,562 @@
+/*
+ * Copyright (C) 2012 The CyanogenMod Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.omnirom.omnigears.interfacesettings;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Fragment;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.Intent.ShortcutIconResource;
+import android.content.res.Resources;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.InsetDrawable;
+import android.graphics.drawable.LayerDrawable;
+import android.graphics.drawable.StateListDrawable;
+import android.net.Uri;
+import android.os.Bundle;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.ImageButton;
+import android.widget.Toast;
+
+import com.android.internal.util.cm.LockscreenTargetUtils;
+import com.android.internal.widget.multiwaveview.GlowPadView;
+import com.android.internal.widget.multiwaveview.TargetDrawable;
+import com.android.settings.R;
+import org.omnirom.omnigears.interfacesettings.IconPicker.OnIconPickListener;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+
+public class LockscreenTargets extends Fragment implements
+        ShortcutPickHelper.OnPickListener, GlowPadView.OnTriggerListener, OnIconPickListener {
+    private static final String TAG = "LockscreenTargets";
+
+    private Activity mActivity;
+    private Resources mResources;
+    private ShortcutPickHelper mPicker;
+    private IconPicker mIconPicker;
+
+    private GlowPadView mWaveView;
+    private ViewGroup mContainer;
+
+    private ImageButton mDialogIcon;
+    private Button mDialogLabel;
+
+    private ArrayList<TargetInfo> mTargetStore = new ArrayList<TargetInfo>();
+    private int mTargetOffset;
+    private int mMaxTargets;
+
+    private File mTemporaryImage;
+    private int mTargetIndex = 0;
+    private static String mEmptyLabel;
+
+    private static final int MENU_RESET = Menu.FIRST;
+    private static final int MENU_SAVE = Menu.FIRST + 1;
+
+    private static class TargetInfo {
+        String uri;
+        String packageName;
+        StateListDrawable icon;
+        Drawable defaultIcon;
+        String iconType;
+        String iconSource;
+    }
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+            Bundle savedInstanceState) {
+        mContainer = container;
+
+        setHasOptionsMenu(true);
+
+        mActivity = getActivity();
+        mResources = getResources();
+
+        mTargetOffset = LockscreenTargetUtils.getTargetOffset(mActivity);
+        mMaxTargets = LockscreenTargetUtils.getMaxTargets(mActivity);
+
+        mIconPicker = new IconPicker(mActivity, this);
+        mPicker = new ShortcutPickHelper(mActivity, this);
+
+        mTemporaryImage = new File(mActivity.getCacheDir() + "/target.tmp");
+        mEmptyLabel = mResources.getString(R.string.lockscreen_target_empty);
+
+        return inflater.inflate(R.layout.lockscreen_targets, container, false);
+    }
+
+    @Override
+    public void onActivityCreated(Bundle savedInstanceState) {
+        super.onActivityCreated(savedInstanceState);
+
+        mWaveView = (GlowPadView) mActivity.findViewById(R.id.lock_target);
+        Drawable handle = LockscreenTargetUtils.getDrawableFromResources(mActivity, null, "ic_lockscreen_handle", false);
+        mWaveView.setHandleDrawable(handle);
+        mWaveView.setOnTriggerListener(this);
+
+        initializeView(Settings.System.getString(mActivity.getContentResolver(),
+                Settings.System.LOCKSCREEN_TARGETS));
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+        // If running on a phone, remove padding around container
+        if (!LockscreenTargetUtils.isScreenLarge(mActivity)) {
+            mContainer.setPadding(0, 0, 0, 0);
+        }
+    }
+
+    @Override
+    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+        menu.add(0, MENU_RESET, 0, R.string.reset)
+            .setIcon(R.drawable.ic_settings_backup) // use the backup icon
+            .setAlphabeticShortcut('r')
+            .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM |
+                MenuItem.SHOW_AS_ACTION_WITH_TEXT);
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        switch (item.getItemId()) {
+            case MENU_RESET:
+                resetAll();
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    private void initializeView(String input) {
+        if (input == null) {
+            input = LockscreenTargetUtils.EMPTY_TARGET;
+        }
+
+        mTargetStore.clear();
+
+        final Drawable activeBack = LockscreenTargetUtils.getDrawableFromResources(
+                mActivity, null, "ic_lockscreen_target_activated" ,false);
+        final String[] targetStore = input.split("\\|");
+
+        for (int i = 0; i < mTargetOffset; i++) {
+            mTargetStore.add(new TargetInfo());
+        }
+
+        //Add the unlock icon
+        Drawable unlockFront = LockscreenTargetUtils.getDrawableFromResources(
+                mActivity, null, "ic_lockscreen_unlock_normal" ,false);
+        Drawable unlockBack = LockscreenTargetUtils.getDrawableFromResources(
+                mActivity, null, "ic_lockscreen_unlock_activated" ,false);
+        TargetInfo unlockTarget = new TargetInfo();
+        unlockTarget.icon = LockscreenTargetUtils.getLayeredDrawable(
+                mActivity, unlockBack, unlockFront, 0, true);
+        mTargetStore.add(unlockTarget);
+
+        for (int i = 0; i < 8 - mTargetOffset - 1; i++) {
+            if (i >= mMaxTargets) {
+                mTargetStore.add(new TargetInfo());
+                continue;
+            }
+
+            Drawable front = null;
+            Drawable back = activeBack;
+            boolean frontBlank = false;
+            TargetInfo info = new TargetInfo();
+            info.uri = i < targetStore.length ? targetStore[i] : LockscreenTargetUtils.EMPTY_TARGET;
+
+             if (!info.uri.equals(LockscreenTargetUtils.EMPTY_TARGET)) {
+                try {
+                    Intent intent = Intent.parseUri(info.uri, 0);
+                    if (intent.hasExtra(LockscreenTargetUtils.ICON_FILE)) {
+                        info.iconType = LockscreenTargetUtils.ICON_FILE;
+                        info.iconSource = intent.getStringExtra(LockscreenTargetUtils.ICON_FILE);
+                        front = LockscreenTargetUtils.getDrawableFromFile(mActivity,
+                                info.iconSource);
+                    } else if (intent.hasExtra(LockscreenTargetUtils.ICON_RESOURCE)) {
+                        info.iconType = LockscreenTargetUtils.ICON_RESOURCE;
+                        info.iconSource = intent.getStringExtra(LockscreenTargetUtils.ICON_RESOURCE);
+                        info.packageName = intent.getStringExtra(LockscreenTargetUtils.ICON_PACKAGE);
+
+                        if (info.iconSource != null) {
+                            front = LockscreenTargetUtils.getDrawableFromResources(mActivity,
+                                    null, info.iconSource, false);
+                            back = LockscreenTargetUtils.getDrawableFromResources(mActivity,
+                                    null, info.iconSource, true);
+                            frontBlank = true;
+                        }
+                    }
+                    if (front == null) {
+                        info.iconType = null;
+                        front = LockscreenTargetUtils.getDrawableFromIntent(mActivity, intent);
+                    }
+                } catch (URISyntaxException e) {
+                    Log.w(TAG, "Invalid lockscreen target " + info.uri);
+                }
+            }
+
+            if (front == null) {
+                front = mResources.getDrawable(R.drawable.ic_empty);
+            }
+            if (back == null) {
+                back = activeBack;
+            }
+
+            int inset = LockscreenTargetUtils.getInsetForIconType(mActivity, info.iconType);
+            info.icon = LockscreenTargetUtils.getLayeredDrawable(mActivity,
+                    back, front, inset, frontBlank);
+            info.defaultIcon = front;
+
+            mTargetStore.add(info);
+        }
+
+        ArrayList<TargetDrawable> targetDrawables = new ArrayList<TargetDrawable>();
+        for (TargetInfo i : mTargetStore) {
+            targetDrawables.add(new TargetDrawable(mResources, i != null ? i.icon : null));
+        }
+        mWaveView.setTargetResources(targetDrawables);
+    }
+
+    /**
+     * Resets the target layout to stock
+     */
+    private void resetAll() {
+        new AlertDialog.Builder(mActivity)
+                .setTitle(R.string.lockscreen_target_reset_title)
+                .setIconAttribute(android.R.attr.alertDialogIcon)
+                .setMessage(R.string.lockscreen_target_reset_message)
+                .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
+                    @Override
+                    public void onClick(DialogInterface dialog, int id) {
+                        initializeView(null);
+                        Settings.System.putString(mActivity.getContentResolver(),
+                                Settings.System.LOCKSCREEN_TARGETS, null);
+                        Toast.makeText(mActivity, R.string.lockscreen_target_reset,
+                                Toast.LENGTH_LONG).show();
+                    }
+                })
+                .setNegativeButton(R.string.cancel, null)
+                .show();
+    }
+
+    /**
+     * Save targets to settings provider
+     */
+    private void saveAll() {
+        StringBuilder targetLayout = new StringBuilder();
+        ArrayList<String> existingImages = new ArrayList<String>();
+        boolean hasValidTargets = false;
+
+        for (int i = mTargetOffset + 1; i <= mTargetOffset + mMaxTargets; i++) {
+            TargetInfo info = mTargetStore.get(i);
+            String uri = info.uri;
+
+            if (info.iconSource != null) {
+                existingImages.add(info.iconSource);
+            }
+
+            if (!TextUtils.equals(uri, LockscreenTargetUtils.EMPTY_TARGET)) {
+                try {
+                    Intent intent = Intent.parseUri(info.uri, 0);
+                    // make sure to remove any outdated icon references
+                    intent.removeExtra(LockscreenTargetUtils.ICON_RESOURCE);
+                    intent.removeExtra(LockscreenTargetUtils.ICON_FILE);
+                    if (info.iconType != null) {
+                        intent.putExtra(info.iconType, info.iconSource);
+                    }
+                    if (LockscreenTargetUtils.ICON_RESOURCE.equals(info.iconType)
+                            && info.packageName != null) {
+                        intent.putExtra(LockscreenTargetUtils.ICON_PACKAGE, info.packageName);
+                    } else {
+                        intent.removeExtra(LockscreenTargetUtils.ICON_PACKAGE);
+                    }
+
+                    uri = intent.toUri(0);
+                    hasValidTargets = true;
+                } catch (URISyntaxException e) {
+                    Log.w(TAG, "Invalid uri " + info.uri + " on save, ignoring");
+                    uri = LockscreenTargetUtils.EMPTY_TARGET;
+                }
+            }
+
+            if (targetLayout.length() > 0) {
+                targetLayout.append("|");
+            }
+            targetLayout.append(uri);
+        }
+
+        final String targets = hasValidTargets ? targetLayout.toString() : null;
+        Settings.System.putString(mActivity.getContentResolver(),
+                Settings.System.LOCKSCREEN_TARGETS, targets);
+
+        for (File image : mActivity.getFilesDir().listFiles()) {
+            if (image.getName().startsWith("lockscreen_")
+                    && !existingImages.contains(image.getAbsolutePath())) {
+                image.delete();
+            }
+        }
+    }
+
+    /**
+     * Updates a target in the GlowPadView
+     */
+    private void setTarget(int position, String uri, Drawable drawable,
+            String iconType, String iconSource, String packageName) {
+        TargetInfo item = mTargetStore.get(position);
+        StateListDrawable state = (StateListDrawable) item.icon;
+        LayerDrawable inactiveLayer = (LayerDrawable) state.getStateDrawable(0);
+        LayerDrawable activeLayer = (LayerDrawable) state.getStateDrawable(1);
+        boolean hasBackground = false;
+
+        inactiveLayer.setDrawableByLayerId(1, drawable);
+
+        if (LockscreenTargetUtils.ICON_RESOURCE.equals(iconType) && iconSource != null) {
+            InsetDrawable empty = new InsetDrawable(
+                    mResources.getDrawable(android.R.color.transparent), 0, 0, 0, 0);
+            activeLayer.setDrawableByLayerId(1, empty);
+            Drawable back = LockscreenTargetUtils.getDrawableFromResources(mActivity,
+                    packageName, iconSource, true);
+            if (back != null) {
+                activeLayer.setDrawableByLayerId(0, back);
+                hasBackground = true;
+            }
+        } else {
+            activeLayer.setDrawableByLayerId(1, drawable);
+        }
+
+        if (!hasBackground) {
+            final Drawable activeBack = LockscreenTargetUtils.getDrawableFromResources(
+                    mActivity, null, "ic_lockscreen_target_activated", false);
+            activeLayer.setDrawableByLayerId(0, new InsetDrawable(activeBack, 0, 0, 0, 0));
+        }
+
+        item.defaultIcon = getPickedIconFromDialog();
+        item.uri = uri;
+        item.iconType = iconType;
+        item.iconSource = iconSource;
+        item.packageName = packageName;
+
+        saveAll();
+    }
+
+    private Drawable getPickedIconFromDialog() {
+        return mDialogIcon.getDrawable().mutate();
+    }
+
+    private void setIconForDialog(Drawable icon) {
+        // need to mutate the drawable here to not share drawable state with GlowPadView
+        mDialogIcon.setImageDrawable(icon.getConstantState().newDrawable().mutate());
+    }
+
+    @Override
+    public void shortcutPicked(String uri, String friendlyName, boolean isApplication) {
+        if (uri == null) {
+            return;
+        }
+
+        try {
+            Intent intent = Intent.parseUri(uri, 0);
+            Drawable icon = LockscreenTargetUtils.getDrawableFromIntent(mActivity, intent);
+
+            mDialogLabel.setText(friendlyName);
+            mDialogLabel.setTag(uri);
+            // this is a fresh drawable, so we can assign it directly
+            mDialogIcon.setImageDrawable(icon);
+            mDialogIcon.setTag(null);
+        } catch (URISyntaxException e) {
+            Log.wtf(TAG, "Invalid uri " + uri + " on pick");
+        }
+    }
+
+    @Override
+    public void onActivityResult(int requestCode, int resultCode, Intent data) {
+        String shortcutName = null;
+        if (data != null) {
+            shortcutName = data.getStringExtra(Intent.EXTRA_SHORTCUT_NAME);
+        }
+
+        if (TextUtils.equals(shortcutName, mEmptyLabel)) {
+            mDialogLabel.setText(mEmptyLabel);
+            mDialogLabel.setTag(LockscreenTargetUtils.EMPTY_TARGET);
+            mDialogIcon.setImageResource(R.drawable.ic_empty);
+            mDialogIcon.setTag(null);
+        } else if (requestCode == IconPicker.REQUEST_PICK_SYSTEM
+                || requestCode == IconPicker.REQUEST_PICK_GALLERY
+                || requestCode == IconPicker.REQUEST_PICK_ICON_PACK) {
+            mIconPicker.onActivityResult(requestCode, resultCode, data);
+        } else if (requestCode != Activity.RESULT_CANCELED
+                && resultCode != Activity.RESULT_CANCELED) {
+            mPicker.onActivityResult(requestCode, resultCode, data);
+        }
+    }
+
+    @Override
+    public void onGrabbed(View v, int handle) {
+    }
+
+    @Override
+    public void onReleased(View v, int handle) {
+    }
+
+    @Override
+    public void onTrigger(View v, final int target) {
+        mTargetIndex = target;
+
+        if (target == mTargetOffset) {
+            mWaveView.reset(true);
+            return;
+        }
+
+        new AlertDialog.Builder(mActivity)
+                .setTitle(R.string.lockscreen_target_edit_title)
+                .setView(createShortcutDialogView(target))
+                .setPositiveButton(R.string.ok,  new DialogInterface.OnClickListener() {
+                    @Override
+                    public void onClick(DialogInterface dialog, int which) {
+                        TargetInfo info = (TargetInfo) mDialogIcon.getTag();
+                        String type = info != null ? info.iconType : null;
+                        String source = info != null ? info.iconSource : null;
+                        String packageName = info != null ? info.packageName : null;
+                        int inset = LockscreenTargetUtils.getInsetForIconType(mActivity, type);
+
+                        InsetDrawable drawable = new InsetDrawable(getPickedIconFromDialog(),
+                                inset, inset, inset, inset);
+                        setTarget(mTargetIndex, mDialogLabel.getTag().toString(),
+                                drawable, type, source, packageName);
+                    }
+                })
+                .setNegativeButton(R.string.cancel, null)
+                .setCancelable(false)
+                .show();
+    }
+
+    private View createShortcutDialogView(int target) {
+        View view = View.inflate(mActivity, R.layout.lockscreen_shortcut_dialog, null);
+        view.findViewById(R.id.icon).setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                if (!mDialogLabel.getText().equals(mEmptyLabel)) {
+                    try {
+                        mTemporaryImage.createNewFile();
+                        mTemporaryImage.setWritable(true, false);
+                        mIconPicker.pickIcon(getId(), mTemporaryImage);
+                    } catch (IOException e) {
+                        Log.d(TAG, "Could not create temporary icon", e);
+                    }
+                }
+            }
+        });
+        view.findViewById(R.id.label).setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                String[] names = new String[] { mEmptyLabel };
+                ShortcutIconResource[] icons = new ShortcutIconResource[] {
+                    ShortcutIconResource.fromContext(mActivity, android.R.drawable.ic_delete)
+                };
+                mPicker.pickShortcut(names, icons, getId());
+            }
+        });
+
+        mDialogIcon = (ImageButton) view.findViewById(R.id.icon);
+        mDialogLabel = (Button) view.findViewById(R.id.label);
+
+        TargetInfo item = mTargetStore.get(target);
+        setIconForDialog(item.defaultIcon);
+
+        TargetInfo icon = new TargetInfo();
+        icon.iconType = item.iconType;
+        icon.iconSource = item.iconSource;
+        icon.packageName = item.packageName;
+        mDialogIcon.setTag(icon);
+
+        if (TextUtils.equals(item.uri, LockscreenTargetUtils.EMPTY_TARGET)) {
+            mDialogLabel.setText(mEmptyLabel);
+        } else {
+            mDialogLabel.setText(mPicker.getFriendlyNameForUri(item.uri));
+        }
+        mDialogLabel.setTag(item.uri);
+
+        return view;
+    }
+
+    @Override
+    public void onGrabbedStateChange(View v, int handle) {
+    }
+
+    @Override
+    public void iconPicked(int requestCode, int resultCode, Intent intent) {
+        TargetInfo icon = new TargetInfo();
+        Drawable iconDrawable = null;
+
+        if (requestCode == IconPicker.REQUEST_PICK_GALLERY) {
+            if (resultCode == Activity.RESULT_OK) {
+                File imageFile = new File(mActivity.getFilesDir(),
+                        "/lockscreen_" + System.currentTimeMillis() + ".png");
+                if (mTemporaryImage.exists()) {
+                    mTemporaryImage.renameTo(imageFile);
+                }
+                imageFile.setReadOnly();
+
+                icon.iconType = LockscreenTargetUtils.ICON_FILE;
+                icon.iconSource = imageFile.getAbsolutePath();
+                iconDrawable = LockscreenTargetUtils.getDrawableFromFile(
+                        mActivity, icon.iconSource);
+            } else {
+                if (mTemporaryImage.exists()) {
+                    mTemporaryImage.delete();
+                }
+                return;
+            }
+        } else if (requestCode == IconPicker.REQUEST_PICK_SYSTEM) {
+            icon.iconType = LockscreenTargetUtils.ICON_RESOURCE;
+            icon.iconSource = intent.getStringExtra(IconPicker.RESOURCE_NAME);
+            iconDrawable = LockscreenTargetUtils.getDrawableFromResources(mActivity,
+                    null, icon.iconSource, false);
+        } else if (requestCode == IconPicker.REQUEST_PICK_ICON_PACK
+                && resultCode == Activity.RESULT_OK) {
+            icon.packageName = intent.getStringExtra(IconPicker.PACKAGE_NAME);
+            icon.iconType = LockscreenTargetUtils.ICON_RESOURCE;
+            icon.iconSource = intent.getStringExtra(IconPicker.RESOURCE_NAME);
+            iconDrawable = LockscreenTargetUtils.getDrawableFromResources(mActivity,
+                    icon.packageName, icon.iconSource, false);
+        } else {
+            return;
+        }
+
+        if (iconDrawable != null) {
+            mDialogIcon.setTag(icon);
+            setIconForDialog(iconDrawable);
+        } else {
+            Log.w(TAG, "Could not fetch icon, keeping old one (type=" + icon.iconType
+                    + ", source=" + icon.iconSource + ", package= " + icon.packageName + ")");
+        }
+    }
+
+    @Override
+    public void onFinishFinalAnimation() {
+    }
+}
diff --git a/src/org/omnirom/omnigears/interfacesettings/NavRing.java b/src/org/omnirom/omnigears/interfacesettings/NavRing.java
new file mode 100644
index 0000000..6be0b60
--- /dev/null
+++ b/src/org/omnirom/omnigears/interfacesettings/NavRing.java
@@ -0,0 +1,308 @@
+/*
+ * Copyright (C) 2013 The CyanogenMod Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.omnirom.omnigears.interfacesettings;
+
+import android.app.AlertDialog;
+import android.app.Fragment;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.Intent.ShortcutIconResource;
+import android.content.res.Configuration;
+import android.os.Bundle;
+import android.os.Vibrator;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Toast;
+
+import static com.android.internal.util.cm.NavigationRingConstants.*;
+import com.android.internal.util.cm.NavigationRingHelpers;
+import com.android.internal.widget.multiwaveview.GlowPadView;
+import com.android.internal.widget.multiwaveview.TargetDrawable;
+import com.android.settings.R;
+import com.android.settings.Utils;
+
+import java.util.ArrayList;
+
+public class NavRing extends Fragment implements
+        ShortcutPickHelper.OnPickListener, GlowPadView.OnTriggerListener {
+    private GlowPadView mGlowPadView;
+    private ShortcutPickHelper mPicker;
+    private String[] mTargetActivities;
+    private ViewGroup mContainer;
+
+    private int mTargetIndex = 0;
+    private int mStartPosOffset;
+    private int mEndPosOffset;
+
+    private boolean mIsLandscape;
+    private boolean mIsScreenLarge;
+
+    private ActionHolder mActions;
+
+    private static final int MENU_RESET = Menu.FIRST;
+    private static final int MENU_SAVE = Menu.FIRST + 1;
+
+    private class ActionHolder {
+        private ArrayList<CharSequence> mAvailableEntries = new ArrayList<CharSequence>();
+        private ArrayList<String> mAvailableValues = new ArrayList<String>();
+
+        public void addAction(String action, int entryResId) {
+            mAvailableEntries.add(getString(entryResId));
+            mAvailableValues.add(action);
+        }
+        public int getActionIndex(String action) {
+            int count = mAvailableValues.size();
+            for (int i = 0; i < count; i++) {
+                if (TextUtils.equals(mAvailableValues.get(i), action)) {
+                    return i;
+                }
+            }
+            return -1;
+        }
+        public String getAction(int index) {
+            if (index > mAvailableValues.size()) {
+                return null;
+            }
+            return mAvailableValues.get(index);
+        }
+        public CharSequence[] getEntries() {
+            return mAvailableEntries.toArray(new CharSequence[mAvailableEntries.size()]);
+        }
+    };
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+            Bundle savedInstanceState) {
+        mContainer = container;
+        setHasOptionsMenu(true);
+        createActionList();
+
+        mIsScreenLarge = !Utils.isPhone(getActivity());
+        mIsLandscape = getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE;
+
+        mPicker = new ShortcutPickHelper(getActivity(), this);
+
+        return inflater.inflate(R.layout.navigation_ring_targets, container, false);
+    }
+
+    @Override
+    public void onActivityCreated(Bundle savedInstanceState) {
+        super.onActivityCreated(savedInstanceState);
+        mGlowPadView = ((GlowPadView) getActivity().findViewById(R.id.navring_target));
+        mGlowPadView.setOnTriggerListener(this);
+        updateDrawables();
+    }
+
+    private void createActionList() {
+        mActions = new ActionHolder();
+        mActions.addAction(ACTION_NONE, R.string.navring_action_none);
+
+        if (NavigationRingHelpers.isAssistantAvailable(getActivity())) {
+            mActions.addAction(ACTION_ASSIST, R.string.navring_action_google_now);
+        }
+        if (NavigationRingHelpers.isTorchAvailable(getActivity())) {
+            mActions.addAction(ACTION_TORCH, R.string.navring_action_torch);
+        }
+
+        mActions.addAction(ACTION_SCREENSHOT, R.string.navring_action_take_screenshot);
+        mActions.addAction(ACTION_IME, R.string.navring_action_open_ime_switcher);
+        mActions.addAction(ACTION_SILENT, R.string.navring_action_ring_silent);
+
+        Vibrator vibrator = (Vibrator) getActivity().getSystemService(Context.VIBRATOR_SERVICE);
+        if (vibrator != null && vibrator.hasVibrator()) {
+            mActions.addAction(ACTION_VIBRATE, R.string.navring_action_ring_vibrate);
+            mActions.addAction(ACTION_RING_SILENT_VIBRATE, R.string.navring_action_ring_vibrate_silent);
+        }
+
+        mActions.addAction(ACTION_KILL, R.string.navring_action_kill_app);
+        mActions.addAction(ACTION_POWER, R.string.navring_action_screen_off);
+
+        mActions.addAction(ACTION_APP, R.string.select_application);
+    }
+
+    private void setDrawables() {
+        final ArrayList<TargetDrawable> targets = new ArrayList<TargetDrawable>();
+        final Context context = getActivity();
+
+        if (!mIsLandscape || mIsScreenLarge) {
+            mStartPosOffset =  1;
+            mEndPosOffset = 4;
+        } else {
+            mStartPosOffset = 3;
+            mEndPosOffset =  2;
+        }
+
+         // Add Initial Place Holder Targets
+        for (int i = 0; i < mStartPosOffset; i++) {
+            targets.add(NavigationRingHelpers.getTargetDrawable(context, null));
+        }
+        // Add User Targets
+        for (int i = 0; i < mTargetActivities.length; i++) {
+            final TargetDrawable drawable =
+                    NavigationRingHelpers.getTargetDrawable(context, mTargetActivities[i]);
+            // we also want empty targets to be selectable here
+            drawable.setEnabled(true);
+            targets.add(drawable);
+        }
+
+        // Add End Place Holder Targets
+        for (int i = 0; i < mEndPosOffset; i++) {
+            targets.add(NavigationRingHelpers.getTargetDrawable(context, null));
+        }
+
+        mGlowPadView.setTargetResources(targets);
+        NavigationRingHelpers.swapSearchIconIfNeeded(context, mGlowPadView);
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+
+        // If running on a phone, remove padding around container
+        if (!mIsScreenLarge) {
+            mContainer.setPadding(0, 0, 0, 0);
+        }
+    }
+
+    @Override
+    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+        menu.add(0, MENU_RESET, 0, R.string.reset)
+            .setIcon(R.drawable.ic_settings_backup)
+            .setAlphabeticShortcut('r')
+            .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM |
+                MenuItem.SHOW_AS_ACTION_WITH_TEXT);
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        switch (item.getItemId()) {
+            case MENU_RESET:
+                resetAll();
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    private void resetAll() {
+        final AlertDialog d = new AlertDialog.Builder(getActivity())
+                .setTitle(R.string.lockscreen_target_reset_title)
+                .setIconAttribute(android.R.attr.alertDialogIcon)
+                .setMessage(R.string.navring_target_reset_message)
+                .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
+                    @Override
+                    public void onClick(DialogInterface dialog, int id) {
+                        NavigationRingHelpers.resetActionsToDefaults(getActivity());
+                        updateDrawables();
+                        Toast.makeText(getActivity(),
+                                R.string.navring_target_reset,
+                                Toast.LENGTH_LONG).show();
+                    }
+                })
+                .setNegativeButton(R.string.cancel, null)
+                .create();
+
+        d.show();
+    }
+
+    private void saveAll() {
+        final ContentResolver cr = getActivity().getContentResolver();
+        for (int i = 0; i < mTargetActivities.length; i++) {
+            Settings.System.putString(cr,
+                    Settings.System.NAVIGATION_RING_TARGETS[i], mTargetActivities[i]);
+        }
+        setDrawables();
+    }
+
+    @Override
+    public void shortcutPicked(String uri, String friendlyName, boolean isApplication) {
+        mTargetActivities[mTargetIndex] = uri;
+        saveAll();
+    }
+
+    @Override
+    public void onActivityResult(int requestCode, int resultCode, Intent data) {
+        mPicker.onActivityResult(requestCode, resultCode, data);
+        super.onActivityResult(requestCode, resultCode, data);
+    }
+
+    private void updateDrawables() {
+        mTargetActivities = NavigationRingHelpers.getTargetActions(getActivity());
+        setDrawables();
+    }
+
+    private void onTargetChange(String uri) {
+        if (uri.equals(ACTION_APP)) {
+            final String label = getResources().getString(R.string.lockscreen_target_empty);
+            final ShortcutIconResource iconResource =
+                    ShortcutIconResource.fromContext(getActivity(), android.R.drawable.ic_delete);
+            mPicker.pickShortcut(
+                    new String[] { label },
+                    new ShortcutIconResource[] { iconResource },
+                    getId());
+        } else {
+            mTargetActivities[mTargetIndex] = uri;
+            saveAll();
+        }
+    }
+
+    @Override
+    public void onTrigger(View v, final int target) {
+        mTargetIndex = target - mStartPosOffset;
+
+        final DialogInterface.OnClickListener l = new DialogInterface.OnClickListener() {
+            @Override
+            public void onClick(DialogInterface dialog, int item) {
+                onTargetChange(mActions.getAction(item));
+                dialog.dismiss();
+            }
+        };
+
+        final int selection = mActions.getActionIndex(mTargetActivities[mTargetIndex]);
+        final AlertDialog dialog = new AlertDialog.Builder(getActivity())
+                .setTitle(R.string.navring_choose_action_title)
+                .setSingleChoiceItems(mActions.getEntries(), selection, l)
+                .create();
+
+        dialog.show();
+    }
+
+    @Override
+    public void onGrabbed(View v, int handle) {
+    }
+
+    @Override
+    public void onReleased(View v, int handle) {
+    }
+
+    @Override
+    public void onGrabbedStateChange(View v, int handle) {
+    }
+
+    @Override
+    public void onFinishFinalAnimation() {
+    }
+}
diff --git a/src/org/omnirom/omnigears/interfacesettings/ShortcutPickHelper.java b/src/org/omnirom/omnigears/interfacesettings/ShortcutPickHelper.java
new file mode 100644
index 0000000..15a115f
--- /dev/null
+++ b/src/org/omnirom/omnigears/interfacesettings/ShortcutPickHelper.java
@@ -0,0 +1,324 @@
+/*
+ * Copyright (C) 2011 The CyanogenMod Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.omnirom.omnigears.interfacesettings;
+
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.AlertDialog.Builder;
+import android.app.Fragment;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.Intent.ShortcutIconResource;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseExpandableListAdapter;
+import android.widget.ExpandableListView;
+import android.widget.TextView;
+
+import com.android.settings.R;
+import org.omnirom.omnigears.interfacesettings.ShortcutPickHelper.AppExpandableAdapter.GroupInfo;
+
+public class ShortcutPickHelper {
+
+    private Activity mParent;
+    private AlertDialog mAlertDialog;
+    private OnPickListener mListener;
+    private PackageManager mPackageManager;
+    private static final int REQUEST_PICK_SHORTCUT = 100;
+    private static final int REQUEST_PICK_APPLICATION = 101;
+    private static final int REQUEST_CREATE_SHORTCUT = 102;
+    private int lastFragmentId;
+
+    public interface OnPickListener {
+        void shortcutPicked(String uri, String friendlyName, boolean isApplication);
+    }
+
+    public ShortcutPickHelper(Activity parent, OnPickListener listener) {
+        mParent = parent;
+        mPackageManager = mParent.getPackageManager();
+        mListener = listener;
+    }
+
+    public void onActivityResult(int requestCode, int resultCode, Intent data) {
+        if (resultCode == Activity.RESULT_OK) {
+            switch (requestCode) {
+            case REQUEST_PICK_APPLICATION:
+                completeSetCustomApp(data);
+                break;
+            case REQUEST_CREATE_SHORTCUT:
+                completeSetCustomShortcut(data);
+                break;
+            case REQUEST_PICK_SHORTCUT:
+                processShortcut(data, REQUEST_PICK_APPLICATION, REQUEST_CREATE_SHORTCUT);
+                break;
+            }
+        }
+    }
+
+    public void pickShortcut(String[] names, ShortcutIconResource[] icons, int fragmentId) {
+        Bundle bundle = new Bundle();
+
+        ArrayList<String> shortcutNames = new ArrayList<String>();
+        if (names != null) {
+            for (String s : names) {
+                shortcutNames.add(s);
+            }
+        }
+        shortcutNames.add(mParent.getString(R.string.profile_applist_title));
+        shortcutNames.add(mParent.getString(R.string.picker_activities));
+        bundle.putStringArrayList(Intent.EXTRA_SHORTCUT_NAME, shortcutNames);
+
+        ArrayList<ShortcutIconResource> shortcutIcons = new ArrayList<ShortcutIconResource>();
+        if (icons != null) {
+            for (ShortcutIconResource s : icons) {
+                shortcutIcons.add(s);
+            }
+        }
+        shortcutIcons.add(ShortcutIconResource.fromContext(mParent, android.R.drawable.sym_def_app_icon));
+        shortcutIcons.add(ShortcutIconResource.fromContext(mParent, R.drawable.activities_icon));
+        bundle.putParcelableArrayList(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, shortcutIcons);
+
+        Intent pickIntent = new Intent(Intent.ACTION_PICK_ACTIVITY);
+        pickIntent.putExtra(Intent.EXTRA_INTENT, new Intent(Intent.ACTION_CREATE_SHORTCUT));
+        pickIntent.putExtra(Intent.EXTRA_TITLE, mParent.getText(R.string.select_custom_app_title));
+        pickIntent.putExtras(bundle);
+        lastFragmentId = fragmentId;
+        startFragmentOrActivity(pickIntent, REQUEST_PICK_SHORTCUT);
+    }
+
+    private void startFragmentOrActivity(Intent pickIntent, int requestCode) {
+        if (lastFragmentId == 0) {
+            mParent.startActivityForResult(pickIntent, requestCode);
+        } else {
+            Fragment cFrag = mParent.getFragmentManager().findFragmentById(lastFragmentId);
+            if (cFrag != null) {
+                mParent.startActivityFromFragment(cFrag, pickIntent, requestCode);
+            }
+        }
+    }
+
+    private void processShortcut(final Intent intent, int requestCodeApplication, int requestCodeShortcut) {
+        // Handle case where user selected "Applications"
+        String applicationName = mParent.getString(R.string.profile_applist_title);
+        String application2name = mParent.getString(R.string.picker_activities);
+        String shortcutName = intent.getStringExtra(Intent.EXTRA_SHORTCUT_NAME);
+        if (applicationName != null && applicationName.equals(shortcutName)) {
+            Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
+            mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
+
+            Intent pickIntent = new Intent(Intent.ACTION_PICK_ACTIVITY);
+            pickIntent.putExtra(Intent.EXTRA_INTENT, mainIntent);
+            startFragmentOrActivity(pickIntent, requestCodeApplication);
+        } else if (application2name != null && application2name.equals(shortcutName)){
+            final List<PackageInfo> pInfos = mPackageManager.getInstalledPackages(PackageManager.GET_ACTIVITIES);
+            ExpandableListView appListView = new ExpandableListView(mParent);
+            AppExpandableAdapter appAdapter = new AppExpandableAdapter(pInfos, mParent);
+            appListView.setAdapter(appAdapter);
+            appListView.setOnChildClickListener(new ExpandableListView.OnChildClickListener() {
+                @Override
+                public boolean onChildClick(ExpandableListView parent, View v,
+                        int groupPosition, int childPosition, long id) {
+                    Intent shortIntent = new Intent(Intent.ACTION_MAIN);
+                    String pkgName = ((GroupInfo)parent.getExpandableListAdapter().getGroup(groupPosition))
+                            .info.packageName;
+                    String actName = ((GroupInfo)parent.getExpandableListAdapter().getGroup(groupPosition))
+                            .info.activities[childPosition].name;
+                    shortIntent.setClassName(pkgName, actName);
+                    completeSetCustomApp(shortIntent);
+                    mAlertDialog.dismiss();
+                    return true;
+                }
+            });
+            Builder builder = new Builder(mParent);
+            builder.setView(appListView);
+            mAlertDialog = builder.create();
+            mAlertDialog.setTitle(mParent.getString(R.string.select_custom_activity_title));
+            mAlertDialog.show();
+            mAlertDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
+                @Override
+                public void onCancel(DialogInterface dialog) {
+                    mListener.shortcutPicked(null, null, false);
+                }
+            });
+        } else {
+            startFragmentOrActivity(intent, requestCodeShortcut);
+        }
+    }
+
+    public class AppExpandableAdapter extends BaseExpandableListAdapter {
+
+        ArrayList<GroupInfo> allList = new ArrayList<GroupInfo>();
+        final int groupPadding;
+
+        public class LabelCompare implements Comparator<GroupInfo>{
+            @Override
+            public int compare(GroupInfo item1, GroupInfo item2) {
+                String rank1 = item1.label.toLowerCase();
+                String rank2 = item2.label.toLowerCase();
+                int result = rank1.compareTo(rank2);
+                if(result == 0) {
+                    return 0;
+                } else if(result < 0) {
+                    return -1;
+                } else {
+                    return +1;
+                }
+            }
+        }
+
+        class GroupInfo {
+            String label;
+            PackageInfo info;
+            GroupInfo (String l, PackageInfo p) {
+                label = l;
+                info = p;
+            }
+        }
+
+        public AppExpandableAdapter(List<PackageInfo> pInfos, Context context) {
+            for (PackageInfo i : pInfos) {
+                allList.add(new GroupInfo(i.applicationInfo.loadLabel(mPackageManager).toString(), i));
+            }
+            Collections.sort(allList, new LabelCompare());
+            groupPadding = context.getResources().getDimensionPixelSize(R.dimen.shortcut_picker_left_padding);
+        }
+
+        public String getChild(int groupPosition, int childPosition) {
+            return allList.get(groupPosition).info.activities[childPosition].name;
+        }
+
+        public long getChildId(int groupPosition, int childPosition) {
+            return childPosition;
+        }
+
+        public int getChildrenCount(int groupPosition) {
+            if (allList.get(groupPosition).info.activities != null) {
+                return allList.get(groupPosition).info.activities.length;
+            } else {
+                return 0;
+            }
+        }
+
+
+        public View getChildView(int groupPosition, int childPosition, boolean isLastChild,
+                View convertView, ViewGroup parent) {
+            if (convertView == null) {
+                convertView = View.inflate(mParent, android.R.layout.simple_list_item_1, null);
+                convertView.setPadding(groupPadding, 0, 0, 0);
+
+            }
+            TextView textView = (TextView)convertView.findViewById(android.R.id.text1);
+            textView.setText(getChild(groupPosition, childPosition).replaceFirst(allList.get(groupPosition).info.packageName + ".", ""));
+            return convertView;
+        }
+
+        public GroupInfo getGroup(int groupPosition) {
+            return allList.get(groupPosition);
+        }
+
+        public int getGroupCount() {
+            return allList.size();
+        }
+
+        public long getGroupId(int groupPosition) {
+            return groupPosition;
+        }
+
+        public View getGroupView(int groupPosition, boolean isExpanded, View convertView,
+                ViewGroup parent) {
+            if (convertView == null) {
+                convertView = View.inflate(mParent, android.R.layout.simple_list_item_1, null);
+                convertView.setPadding(70, 0, 0, 0);
+            }
+            TextView textView = (TextView)convertView.findViewById(android.R.id.text1);
+            textView.setText(getGroup(groupPosition).label.toString());
+            return convertView;
+        }
+
+        public boolean isChildSelectable(int groupPosition, int childPosition) {
+            return true;
+        }
+
+        public boolean hasStableIds() {
+            return true;
+        }
+
+    }
+
+    private void completeSetCustomApp(Intent data) {
+        mListener.shortcutPicked(data.toUri(0), getFriendlyActivityName(data, false), true);
+    }
+
+    private void completeSetCustomShortcut(Intent data) {
+        Intent intent = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_INTENT);
+        /* preserve shortcut name, we want to restore it later */
+        intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, data.getStringExtra(Intent.EXTRA_SHORTCUT_NAME));
+        String appUri = intent.toUri(0);
+        appUri = appUri.replaceAll("com.android.contacts.action.QUICK_CONTACT", "android.intent.action.VIEW");
+        mListener.shortcutPicked(appUri, getFriendlyShortcutName(intent), false);
+    }
+
+    private String getFriendlyActivityName(Intent intent, boolean labelOnly) {
+        ActivityInfo ai = intent.resolveActivityInfo(mPackageManager, PackageManager.GET_ACTIVITIES);
+        String friendlyName = null;
+        if (ai != null) {
+            friendlyName = ai.loadLabel(mPackageManager).toString();
+            if (friendlyName == null && !labelOnly) {
+                friendlyName = ai.name;
+            }
+        }
+        return friendlyName != null || labelOnly ? friendlyName : intent.toUri(0);
+    }
+
+    private String getFriendlyShortcutName(Intent intent) {
+        String activityName = getFriendlyActivityName(intent, true);
+        String name = intent.getStringExtra(Intent.EXTRA_SHORTCUT_NAME);
+
+        if (activityName != null && name != null) {
+            return activityName + ": " + name;
+        }
+        return name != null ? name : intent.toUri(0);
+    }
+
+    public String getFriendlyNameForUri(String uri) {
+        if (uri == null) {
+            return null;
+        }
+
+        try {
+            Intent intent = Intent.parseUri(uri, 0);
+            if (Intent.ACTION_MAIN.equals(intent.getAction())) {
+                return getFriendlyActivityName(intent, false);
+            }
+            return getFriendlyShortcutName(intent);
+        } catch (URISyntaxException e) {
+        }
+
+        return uri;
+    }
+}