Building a Mobile Employee Directory – Step 7: Create an App Widget with it’s own ContentProvider & Service.
For the source code relating to this post, checkout this Github repository.
Continuing with the mobile employee directory example, I’ve added three App Widgets to embed information on the phone’s main screen.
- Create EmployeeWidgetProvider (Changes every 30 minutes, with a random selection. Click to view Employee in DetailActivity.)
- Create EmployeeWidgetProvider2 & EmployeeWidgetService2 (Changes when clicked, with a random selection)
- Create EmployeeStackWidgetProvider & EmployeeStackWidgetService (Changes when scrolled. Click to view Employee in DetailActivity.)
- Create WidgetItem
- Create appwidget_background.xml (in res/drawable)
- Create stack_widget_item_background.xml (in res/drawable)
- Create preview1.png (in res/drawable)
- Create preview2.png (in res/drawable)
- Create stack_widget_item.xml (in res/layout)
- Create stack_widget_layout.xml (in res/layout)
- Create widget_layout.xml (in res/layout)
- Create stack_widget.xml (in res/xml)
- Create widget.xml (in res/xml)
- Modify dimens.xml (in res/values)
- Modify strings.xml (in res/values)
- Modify AndroidManifest.xml
EmployeeWidgetProvider.java
package com.himebaugh.employeedirectory; import java.io.IOException; import java.io.InputStream; import java.util.Random; import android.app.PendingIntent; import android.appwidget.AppWidgetManager; import android.appwidget.AppWidgetProvider; import android.content.ComponentName; import android.content.ContentUris; import android.content.Context; import android.content.Intent; import android.database.Cursor; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.net.Uri; import android.widget.RemoteViews; public class EmployeeWidgetProvider extends AppWidgetProvider{ private int mID; private String mName; private String mTitle; private String mDepartment; private String mPicture; @Override public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { // Get all ids ComponentName thisWidget = new ComponentName(context, EmployeeWidgetProvider.class); int[] allWidgetIds = appWidgetManager.getAppWidgetIds(thisWidget); for (int widgetId : allWidgetIds) { // Select a random employee mID = (new Random().nextInt(11) + 1); Uri uri = ContentUris.withAppendedId(EmployeeProvider.CONTENT_URI, mID); String[] projection = { EmployeeDatabase.COLUMN_ID, EmployeeDatabase.COLUMN_FIRSTNAME, EmployeeDatabase.COLUMN_LASTNAME, EmployeeDatabase.COLUMN_TITLE, EmployeeDatabase.COLUMN_DEPARTMENT, EmployeeDatabase.COLUMN_CITY, EmployeeDatabase.COLUMN_OFFICE_PHONE, EmployeeDatabase.COLUMN_MOBILE_PHONE, EmployeeDatabase.COLUMN_EMAIL, EmployeeDatabase.COLUMN_PICTURE }; String selection = null; String[] selectionArgs = null; String sortOrder = EmployeeDatabase.COLUMN_LASTNAME + " COLLATE LOCALIZED ASC"; Cursor cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, sortOrder); if (cursor != null && cursor.getCount() > 0) { cursor.moveToFirst(); mName = cursor.getString(cursor.getColumnIndex(EmployeeDatabase.COLUMN_LASTNAME)) + ", " + cursor.getString(cursor.getColumnIndex(EmployeeDatabase.COLUMN_FIRSTNAME)); mTitle = cursor.getString(cursor.getColumnIndex(EmployeeDatabase.COLUMN_TITLE)); mDepartment = cursor.getString(cursor.getColumnIndex(EmployeeDatabase.COLUMN_DEPARTMENT)); mPicture = cursor.getString(cursor.getColumnIndex(EmployeeDatabase.COLUMN_PICTURE)); } else { mName = "empty cursor"; } cursor.close(); RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.widget_layout); // Set the text remoteViews.setTextViewText(R.id.appwidget_layout_name, mName); remoteViews.setTextViewText(R.id.appwidget_layout_title, mTitle); remoteViews.setTextViewText(R.id.appwidget_layout_department, mDepartment); InputStream is; try { is = context.getAssets().open("pics/" + mPicture); Bitmap bit = BitmapFactory.decodeStream(is); remoteViews.setImageViewBitmap(R.id.appwidget_layout_picture, bit); } catch (IOException e) { e.printStackTrace(); } Uri details = Uri.withAppendedPath(EmployeeProvider.CONTENT_URI, "" + mID); Intent intent = new Intent(Intent.ACTION_VIEW, details); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); // ?? PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); remoteViews.setOnClickPendingIntent(R.id.appwidget_layout_text, pendingIntent); appWidgetManager.updateAppWidget(widgetId, remoteViews); } } }
EmployeeWidgetProvider2.java
package com.himebaugh.employeedirectory; import android.appwidget.AppWidgetManager; import android.appwidget.AppWidgetProvider; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.util.Log; public class EmployeeWidgetProvider2 extends AppWidgetProvider { @Override public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { // Get all ids ComponentName thisWidget = new ComponentName(context, EmployeeWidgetProvider2.class); int[] allWidgetIds = appWidgetManager.getAppWidgetIds(thisWidget); // Build the intent to call the service Intent intent = new Intent(context.getApplicationContext(), EmployeeWidgetService2.class); intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, allWidgetIds); // Update the widgets via the service context.startService(intent); } }
EmployeeWidgetService2.java
package com.himebaugh.employeedirectory; import java.io.IOException; import java.io.InputStream; import java.util.Random; import android.app.PendingIntent; import android.app.Service; import android.appwidget.AppWidgetManager; import android.content.ComponentName; import android.content.ContentUris; import android.content.Intent; import android.database.Cursor; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.net.Uri; import android.os.IBinder; import android.widget.RemoteViews; public class EmployeeWidgetService2 extends Service { private int mID; private String mName; private String mTitle; private String mDepartment; private String mPicture; @Override public void onStart(Intent intent, int startId) { AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(this.getApplicationContext()); int[] allWidgetIds = intent.getIntArrayExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS); ComponentName thisWidget = new ComponentName(getApplicationContext(), EmployeeWidgetProvider2.class); int[] allWidgetIds2 = appWidgetManager.getAppWidgetIds(thisWidget); for (int widgetId : allWidgetIds) { // Select a random employee mID = (new Random().nextInt(11) + 1); Uri uri = ContentUris.withAppendedId(EmployeeProvider.CONTENT_URI, mID); String[] projection = { EmployeeDatabase.COLUMN_ID, EmployeeDatabase.COLUMN_FIRSTNAME, EmployeeDatabase.COLUMN_LASTNAME, EmployeeDatabase.COLUMN_TITLE, EmployeeDatabase.COLUMN_DEPARTMENT, EmployeeDatabase.COLUMN_CITY, EmployeeDatabase.COLUMN_OFFICE_PHONE, EmployeeDatabase.COLUMN_MOBILE_PHONE, EmployeeDatabase.COLUMN_EMAIL, EmployeeDatabase.COLUMN_PICTURE }; String selection = null; String[] selectionArgs = null; String sortOrder = EmployeeDatabase.COLUMN_LASTNAME + " COLLATE LOCALIZED ASC"; Cursor cursor = this.getApplicationContext().getContentResolver().query(uri, projection, selection, selectionArgs, sortOrder); if (cursor != null && cursor.getCount() > 0) { cursor.moveToFirst(); mName = cursor.getString(cursor.getColumnIndex(EmployeeDatabase.COLUMN_LASTNAME)) + ", " + cursor.getString(cursor.getColumnIndex(EmployeeDatabase.COLUMN_FIRSTNAME)); mTitle = cursor.getString(cursor.getColumnIndex(EmployeeDatabase.COLUMN_TITLE)); mDepartment = cursor.getString(cursor.getColumnIndex(EmployeeDatabase.COLUMN_DEPARTMENT)); mPicture = cursor.getString(cursor.getColumnIndex(EmployeeDatabase.COLUMN_PICTURE)); } else { mName = "empty cursor"; } cursor.close(); RemoteViews remoteViews = new RemoteViews(this.getApplicationContext().getPackageName(), R.layout.widget_layout); // Set the text remoteViews.setTextViewText(R.id.appwidget_layout_name, mName); remoteViews.setTextViewText(R.id.appwidget_layout_title, mTitle); remoteViews.setTextViewText(R.id.appwidget_layout_department, mDepartment); InputStream is; try { is = getAssets().open("pics/" + mPicture ); Bitmap bit = BitmapFactory.decodeStream(is); remoteViews.setImageViewBitmap(R.id.appwidget_layout_picture, bit); } catch (IOException e) { e.printStackTrace(); } // Register an onClickListener Intent clickIntent = new Intent(this.getApplicationContext(), EmployeeWidgetProvider2.class); clickIntent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE); clickIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, allWidgetIds); PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 0, clickIntent, PendingIntent.FLAG_UPDATE_CURRENT); remoteViews.setOnClickPendingIntent(R.id.appwidget_layout_text, pendingIntent); appWidgetManager.updateAppWidget(widgetId, remoteViews); // } stopSelf(); super.onStart(intent, startId); } @Override public IBinder onBind(Intent intent) { return null; } }
EmployeeStackWidgetProvider.java
package com.himebaugh.employeedirectory; import android.annotation.TargetApi; import android.app.PendingIntent; import android.appwidget.AppWidgetManager; import android.appwidget.AppWidgetProvider; import android.content.Context; import android.content.Intent; import android.net.Uri; import android.os.Build; import android.widget.RemoteViews; import android.widget.Toast; @TargetApi(Build.VERSION_CODES.HONEYCOMB) public class EmployeeStackWidgetProvider extends AppWidgetProvider { public static final String TOAST_ACTION = "com.example.android.stackwidget.TOAST_ACTION"; public static final String CLICK_ACTION = "com.himebaugh.employeedirectory.stackwidget.CLICK_ACTION"; public static final String EXTRA_ITEM = "com.himebaugh.employeedirectory.stackwidget.EXTRA_ITEM"; public static final String EMPLOYEE_ID = "com.himebaugh.employeedirectory.stackwidget.EMPLOYEE_ID"; @Override public void onDeleted(Context context, int[] appWidgetIds) { super.onDeleted(context, appWidgetIds); } @Override public void onDisabled(Context context) { super.onDisabled(context); } @Override public void onEnabled(Context context) { super.onEnabled(context); } @Override public void onReceive(Context context, Intent intent) { AppWidgetManager mgr = AppWidgetManager.getInstance(context); if (intent.getAction().equals(TOAST_ACTION)) { int appWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID); int viewIndex = intent.getIntExtra(EXTRA_ITEM, 0); Toast.makeText(context, "Touched view " + viewIndex, Toast.LENGTH_SHORT).show(); } if (intent.getAction().equals(CLICK_ACTION)) { int appWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID); int empID = intent.getIntExtra(EMPLOYEE_ID, 0); Uri details = Uri.withAppendedPath(EmployeeProvider.CONTENT_URI, "" + empID); Intent detailsIntent = new Intent(Intent.ACTION_VIEW, details); detailsIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); context.startActivity(detailsIntent); } super.onReceive(context, intent); } @Override public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { // update each of the widgets with the remote adapter for (int i = 0; i < appWidgetIds.length; ++i) { Intent intent = new Intent(context, EmployeeStackWidgetService.class); intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetIds[i]); intent.setData(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME))); RemoteViews rv = new RemoteViews(context.getPackageName(), R.layout.stack_widget_layout); rv.setRemoteAdapter(appWidgetIds[i], R.id.stack_view, intent); rv.setEmptyView(R.id.stack_view, R.id.empty_view); Intent clickIntent = new Intent(context, EmployeeStackWidgetProvider.class); clickIntent.setAction(EmployeeStackWidgetProvider.CLICK_ACTION); clickIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetIds[i]); intent.setData(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME))); PendingIntent clickPendingIntent = PendingIntent.getBroadcast(context, 0, clickIntent, PendingIntent.FLAG_UPDATE_CURRENT); rv.setPendingIntentTemplate(R.id.stack_view, clickPendingIntent); appWidgetManager.updateAppWidget(appWidgetIds[i], rv); } super.onUpdate(context, appWidgetManager, appWidgetIds); } }
EmployeeStackWidgetService.java
package com.himebaugh.employeedirectory; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.List; import android.annotation.TargetApi; import android.appwidget.AppWidgetManager; import android.content.ContentUris; import android.content.Context; import android.content.Intent; import android.database.Cursor; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.widget.RemoteViews; import android.widget.RemoteViewsService; @TargetApi(Build.VERSION_CODES.HONEYCOMB) public class EmployeeStackWidgetService extends RemoteViewsService { @Override public RemoteViewsFactory onGetViewFactory(Intent intent) { return new StackRemoteViewsFactory2(this.getApplicationContext(), intent); } } class StackRemoteViewsFactory2 implements RemoteViewsService.RemoteViewsFactory { // private static final int mCount = 10; private int mCount = 0; private List<WidgetItem> mWidgetItems = new ArrayList<WidgetItem>(); private Context mContext; private int mAppWidgetId; private int mID; private String mName; private String mTitle; private String mDepartment; private String mPicture; public StackRemoteViewsFactory2(Context context, Intent intent) { mContext = context; mAppWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID); } public void onCreate() { Uri uri = EmployeeProvider.CONTENT_URI; String[] projection = { EmployeeDatabase.COLUMN_ID, EmployeeDatabase.COLUMN_FIRSTNAME, EmployeeDatabase.COLUMN_LASTNAME, EmployeeDatabase.COLUMN_TITLE, EmployeeDatabase.COLUMN_DEPARTMENT, EmployeeDatabase.COLUMN_CITY, EmployeeDatabase.COLUMN_OFFICE_PHONE, EmployeeDatabase.COLUMN_MOBILE_PHONE, EmployeeDatabase.COLUMN_EMAIL, EmployeeDatabase.COLUMN_PICTURE }; String selection = null; String[] selectionArgs = null; String sortOrder = EmployeeDatabase.COLUMN_LASTNAME + " COLLATE LOCALIZED ASC"; Cursor cursor = mContext.getContentResolver().query(uri, projection, selection, selectionArgs, sortOrder); for (int i = 0; i < cursor.getCount(); i++) { cursor.moveToNext(); mID = cursor.getInt(cursor.getColumnIndex(EmployeeDatabase.COLUMN_ID)); mName = cursor.getString(cursor.getColumnIndex(EmployeeDatabase.COLUMN_LASTNAME)) + ", " + cursor.getString(cursor.getColumnIndex(EmployeeDatabase.COLUMN_FIRSTNAME)); mTitle = cursor.getString(cursor.getColumnIndex(EmployeeDatabase.COLUMN_TITLE)); mDepartment = cursor.getString(cursor.getColumnIndex(EmployeeDatabase.COLUMN_DEPARTMENT)); mPicture = cursor.getString(cursor.getColumnIndex(EmployeeDatabase.COLUMN_PICTURE)); mWidgetItems.add(new WidgetItem(mID, mName, mTitle, mDepartment, mPicture)); mCount = mCount + 1; } cursor.close(); try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } } public void onDestroy() { mWidgetItems.clear(); } public int getCount() { return mCount; } public RemoteViews getViewAt(int position) { RemoteViews rv = new RemoteViews(mContext.getPackageName(), R.layout.stack_widget_item); rv.setTextViewText(R.id.stack_widget_layout_name, mWidgetItems.get(position)._name); rv.setTextViewText(R.id.stack_widget_layout_title, mWidgetItems.get(position)._title); rv.setTextViewText(R.id.stack_widget_layout_department, mWidgetItems.get(position)._department); Bundle extras = new Bundle(); extras.putInt(EmployeeStackWidgetProvider.EMPLOYEE_ID, mWidgetItems.get(position)._empID); Intent fillInIntent = new Intent(); fillInIntent.putExtras(extras); rv.setOnClickFillInIntent(R.id.stack_widget_layout_text, fillInIntent); InputStream is; try { System.out.println("Loading view " + position); is = mContext.getAssets().open("pics/" + mWidgetItems.get(position)._picture); Bitmap bit = BitmapFactory.decodeStream(is); rv.setImageViewBitmap(R.id.stack_widget_layout_picture, bit); } catch (IOException e) { e.printStackTrace(); } return rv; } public RemoteViews getLoadingView() { return null; } public int getViewTypeCount() { return 1; } public long getItemId(int position) { return position; } public boolean hasStableIds() { return true; } public void onDataSetChanged() { } }
WidgetItem.java
package com.himebaugh.employeedirectory; public class WidgetItem { Integer _empID; String _name; String _title; String _department; String _picture; public WidgetItem(Integer empID, String name, String title, String department, String picture) { this._empID = empID; this._name = name; this._title = title; this._department = department; this._picture = picture; } }
appwidget_background.xml
<?xml version="1.0" encoding="UTF-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" > <gradient android:angle="270" android:endColor="#77000000" android:startColor="#77000000" /> </shape>
stack_widget_item_background.xml
<?xml version="1.0" encoding="UTF-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" > <solid android:color="#FF000000" /> <stroke android:width="1dp" android:color="#FFFFFFFF" /> <padding android:bottom="1dp" android:left="0dp" android:right="0dp" android:top="1dp" /> </shape>
stack_widget_item.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/stack_widget_layout_text" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_margin="0dip" android:background="@drawable/stack_widget_item_background" android:orientation="horizontal" > <ImageView android:id="@+id/stack_widget_layout_picture" android:layout_width="fill_parent" android:layout_height="wrap_content" android:contentDescription="@string/employee_photo" android:minHeight="50dp" android:minWidth="50dp" android:src="@drawable/ic_launcher" /> <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:minHeight="65dp" android:minWidth="245dp" android:orientation="vertical" > <TextView android:id="@+id/stack_widget_layout_name" style="@android:style/TextAppearance.Medium" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Loading..." /> <TextView android:id="@+id/stack_widget_layout_title" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Loading2..." /> <TextView android:id="@+id/stack_widget_layout_department" android:layout_width="fill_parent" android:layout_height="wrap_content" android:gravity="right" android:text="Loading3..." /> <TextView android:id="@+id/stack_widget_layout_empid" android:layout_width="fill_parent" android:layout_height="wrap_content" android:visibility="gone" /> </LinearLayout> </LinearLayout>
stack_widget_layout.xml
<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:padding="@dimen/widget_margin" > <StackView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/stack_view" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:loopViews="true" /> <TextView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/empty_view" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@drawable/stack_widget_item_background" android:gravity="center" android:text="@string/empty_view_text" android:textColor="#ffffff" android:textSize="20sp" android:textStyle="bold" /> </FrameLayout>
widget_layout.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/appwidget_layout_text" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_margin="8dip" android:background="@drawable/appwidget_background" > <ImageView android:id="@+id/appwidget_layout_picture" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentLeft="true" android:layout_alignParentTop="true" android:contentDescription="@string/employee_photo" android:minHeight="50dp" android:minWidth="50dp" android:src="@drawable/ic_launcher" /> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" > <TextView android:id="@+id/appwidget_layout_name" style="@android:style/TextAppearance.Medium" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Loading..." /> <TextView android:id="@+id/appwidget_layout_title" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Loading2..." /> <TextView android:id="@+id/appwidget_layout_department" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="right" android:text="Loading3..." /> </LinearLayout> </LinearLayout>
stack_widget.xml
<?xml version="1.0" encoding="utf-8"?> <appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android" android:initialLayout="@layout/stack_widget_layout" android:minHeight="64dp" android:minWidth="278dp" android:previewImage="@drawable/preview2" android:resizeMode="horizontal|vertical" android:updatePeriodMillis="3600000" android:widgetCategory="keyguard|home_screen" > </appwidget-provider>
widget.xml
<?xml version="1.0" encoding="utf-8"?> <appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android" android:initialLayout="@layout/widget_layout" android:minHeight="64dp" android:minWidth="278dp" android:previewImage="@drawable/preview1" android:resizeMode="horizontal|vertical" android:updatePeriodMillis="1800000" android:widgetCategory="keyguard|home_screen" > </appwidget-provider>
dimens.xml
<resources> <!-- Default screen margins, per the Android Design guidelines. --> <dimen name="activity_horizontal_margin">16dp</dimen> <dimen name="activity_vertical_margin">16dp</dimen> <dimen name="widget_margin">8dp</dimen> </resources>
strings.xml
<?xml version="1.0" encoding="utf-8"?> <resources> <string name="app_name">Employee Directory</string> <string name="employee_details">Employee Details</string> <string name="employee_photo">Employee Photo</string> <string name="detail_header1">Call Office</string> <string name="detail_header2">Call Mobile</string> <string name="detail_header3">SMS</string> <string name="detail_header4">Email</string> <string name="place_holder">Text will be replaced</string> <string name="action_settings">Settings</string> <string name="menu_search">Search Quotes</string> <string name="search_hint">"Search employees" </string> <string name="search_instructions">Use the search box in the Action Bar to look up a word</string> <string name="search_settings_description">Where show???</string> <!-- Search failure message. --> <string name="no_results">No results found for \"%s\"</string> <string name="empty_view_text">Empty</string> </resources>
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.himebaugh.employeedirectory" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="17" /> <uses-permission android:name="android.permission.SEND_SMS" /> <uses-permission android:name="android.permission.CALL_PHONE" /> <uses-permission android:name="android.permission.READ_PHONE_STATE" /> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <!-- Main --> <activity android:name="com.himebaugh.employeedirectory.MainActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <!-- Detail --> <activity android:name="com.himebaugh.employeedirectory.DetailActivity" android:label="@string/employee_details" > <intent-filter> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <data android:mimeType="vnd.android.cursor.item/vnd.himebaugh.search.employees" /> </intent-filter> </activity> <!-- Searchable --> <activity android:name=".SearchableActivity" android:launchMode="singleTop" > <intent-filter> <action android:name="android.intent.action.SEARCH" /> </intent-filter> <intent-filter> <action android:name="android.intent.action.VIEW" /> </intent-filter> <meta-data android:name="android.app.searchable" android:resource="@xml/searchable" /> </activity> <!-- Points to searchable activity so the whole app can invoke search. --> <meta-data android:name="android.app.default_searchable" android:value="com.himebaugh.employeedirectory.SearchableActivity" /> <provider android:name="com.himebaugh.employeedirectory.EmployeeProvider" android:authorities="com.himebaugh.employeedirectory.EmployeeProvider" android:multiprocess="true" > </provider> <!-- App Widget 1 --> <receiver android:name=".EmployeeWidgetProvider" android:label="Employee Widget 1" > <intent-filter> <action android:name="android.appwidget.action.APPWIDGET_UPDATE" /> </intent-filter> <meta-data android:name="android.appwidget.provider" android:resource="@xml/widget" /> </receiver> <!-- App Widget 2 w/ Service --> <receiver android:name=".EmployeeWidgetProvider2" android:label="Employee Widget 2" > <intent-filter> <action android:name="android.appwidget.action.APPWIDGET_UPDATE" /> </intent-filter> <meta-data android:name="android.appwidget.provider" android:resource="@xml/widget" /> </receiver> <service android:name=".EmployeeWidgetService2" /> <!-- App Widget 3 (StackWidget) --> <receiver android:name=".EmployeeStackWidgetProvider" android:label="Employee Widget 3" > <intent-filter> <action android:name="android.appwidget.action.APPWIDGET_UPDATE" /> </intent-filter> <meta-data android:name="android.appwidget.provider" android:resource="@xml/stack_widget" /> </receiver> <service android:name=".EmployeeStackWidgetService" android:exported="false" android:permission="android.permission.BIND_REMOTEVIEWS" /> </application> </manifest>
Screenshots of the application
Category: Android Application Development
where are you getting the graphics for preview1.png, preview2.png, @drawable/sms, @drawable/phone, and @drawable/mail. Thanks
For the images @drawable/sms, @drawable/phone, and @drawable/mail
I used the images from here: http://download.macromedia.com/pub/developer/flex/employee-directory-android-flex/flex-mobile-workshop.zip for testing my sample app.
Although I suggest you use your own or default android icons for something you place in the App Store. Image size is 40 px X 40 px
For preview1.png & preview2.png Think I used an app called “widget preview” to capture on my phone. Image size is 768 px X 192 px
Thanks!
For the employee photo, what path are you storing it into? Drawable/res?
assets/pics
Which part of the code is responsible for inputting the images to each employee?
Search this page for “InputStream is;” It appears 3 times in code as the code shows 3 different ways to implement an App Widget. Look at the Try Catch Block of code following the InputStream.
Thanks, your website is very useful for learning android.
I am trying to make the employee image show up but it’s not working. I put a test image called employee.jpg in assets/xml and added employee.jpg in the employee_list.xml but it doesn’t seem to load. Is there a specific resolution I have to make the image? My image is 187×187 pixel.
Edit: I mean I placed the test image in Assets/pics not assets/xml, brain fart.
Ok I got it to work.
I’m glad you got it to work!
I updated the page http://innovativenetsolutions.com/2013/07/android-tutorial-appwidget-with-its-own-contentprovider-service/ with an image of the directory structure that I used.
Image size I used was 160×160.
I had to remove @drawable/ic_launcher in detail_activity
Hey, how come the imageview is controlled in “detail_activity.xml” but in the “employeestackwidgetservice.java”, the code points to rv.setImageViewBitmap(R.id.stack_widget_layout_picture, bit)? stack_widget_layout_picture is in “stack_widget_item.xml” I can’t find the portion of the code that points to “R.id.activity_detail_picture”
Ok found it. It’s in DetailActivity.java, mPicture = (ImageView) findViewById(R.id.activity_detail_picture);
Yes. As project got larger, I only posted new or changed files. DetailActivity.java & activity_detail.xml are in Step 4.
The code has been place on GitHub. Download at https://github.com/langhimebaugh/EmployeeDirectory-Step-07
can u plz tell me how can i add any new employee to this app thru coding???
Hello my friend! I want to say that this post is awesome, great written and include
approximately all important infos. I’d like to see extra posts like
this .
Hi,
Thanks for the wonderful tutorial.Could u please share the final code of the project because there are so many steps /versions of the files??Also how to add organisational chart to it or may be “reporting to”button.Appreciate your quick help