OSDN Git Service

Add print job settings screen.
authorSvetoslav Ganov <svetoslavganov@google.com>
Mon, 23 Sep 2013 22:48:23 +0000 (15:48 -0700)
committerThe Android Automerger <android-build@android.com>
Thu, 26 Sep 2013 23:38:31 +0000 (16:38 -0700)
Added a list of active print jobs to the main print settings
screen. Selecting a print job from there leads to a print job
settings screen with more information about the print job and
actions to change the prit job state such as cancel and restart.

bug:10935736

Change-Id: Idd6826a998309941c3d8478dafe4b039c8ca4f45

Conflicts:
res/values/donottranslate.xml

13 files changed:
res/drawable-hdpi/ic_grayedout_printer.png [new file with mode: 0644]
res/drawable-mdpi/ic_grayedout_printer.png [new file with mode: 0644]
res/drawable-xhdpi/ic_grayedout_printer.png [new file with mode: 0644]
res/layout/empty_print_state.xml [new file with mode: 0644]
res/layout/empty_printers_list_service_enabled.xml [new file with mode: 0644]
res/layout/print_job_summary.xml [new file with mode: 0644]
res/values/donottranslate.xml
res/values/strings.xml
res/xml/print_job_settings.xml [new file with mode: 0644]
res/xml/print_settings.xml
src/com/android/settings/print/PrintJobSettingsFragment.java [new file with mode: 0644]
src/com/android/settings/print/PrintServiceSettingsFragment.java
src/com/android/settings/print/PrintSettingsFragment.java

diff --git a/res/drawable-hdpi/ic_grayedout_printer.png b/res/drawable-hdpi/ic_grayedout_printer.png
new file mode 100644 (file)
index 0000000..5e54970
Binary files /dev/null and b/res/drawable-hdpi/ic_grayedout_printer.png differ
diff --git a/res/drawable-mdpi/ic_grayedout_printer.png b/res/drawable-mdpi/ic_grayedout_printer.png
new file mode 100644 (file)
index 0000000..5e54970
Binary files /dev/null and b/res/drawable-mdpi/ic_grayedout_printer.png differ
diff --git a/res/drawable-xhdpi/ic_grayedout_printer.png b/res/drawable-xhdpi/ic_grayedout_printer.png
new file mode 100644 (file)
index 0000000..5e54970
Binary files /dev/null and b/res/drawable-xhdpi/ic_grayedout_printer.png differ
diff --git a/res/layout/empty_print_state.xml b/res/layout/empty_print_state.xml
new file mode 100644 (file)
index 0000000..135b3dd
--- /dev/null
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 The Android Open Source 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.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/empty_printers_list_service_disabled"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent"
+    android:visibility="gone">
+
+    <LinearLayout
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center"
+        android:gravity="center"
+        android:orientation="vertical">
+
+        <ImageView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginBottom="12dip"
+            android:src="@drawable/ic_grayedout_printer"
+            android:contentDescription="@string/print_service_disabled">
+        </ImageView>
+
+        <TextView
+            android:id="@+id/message"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:textAppearance="?android:attr/textAppearanceLarge"
+            android:textColor="?android:attr/textColorSecondary">
+        </TextView>
+
+    </LinearLayout>
+
+</FrameLayout>
diff --git a/res/layout/empty_printers_list_service_enabled.xml b/res/layout/empty_printers_list_service_enabled.xml
new file mode 100644 (file)
index 0000000..78c8b43
--- /dev/null
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 The Android Open Source 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.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/empty_printers_list_service_enabled"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent"
+    android:visibility="gone">
+
+    <LinearLayout
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center"
+        android:gravity="center"
+        android:orientation="vertical">
+
+        <ImageView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginBottom="12dip"
+            android:src="@drawable/ic_grayedout_printer"
+            android:contentDescription="@string/print_searching_for_printers">
+        </ImageView>
+
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:textAppearance="?android:attr/textAppearanceLarge"
+            android:textColor="?android:attr/textColorSecondary"
+            android:text="@string/print_searching_for_printers">
+        </TextView>
+
+        <ProgressBar
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:indeterminate="true"
+            style="@android:style/Widget.Holo.ProgressBar.Horizontal">
+        </ProgressBar>
+
+    </LinearLayout>
+
+</FrameLayout>
diff --git a/res/layout/print_job_summary.xml b/res/layout/print_job_summary.xml
new file mode 100644 (file)
index 0000000..d755de2
--- /dev/null
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 The Android Open Source 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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="fill_parent"
+    android:layout_height="wrap_content"
+    android:layout_marginStart="15dip"
+    android:layout_marginEnd="6dip"
+    android:minHeight="?android:attr/listPreferredItemHeight"
+    android:gravity="top|start"
+    android:orientation="vertical"
+    android:paddingEnd="?android:attr/scrollbarSize"
+    android:background="?android:attr/selectableItemBackground">
+
+    <View
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:background="?android:attr/listDivider">
+    </View>
+
+    <TextView android:id="@+android:id/summary"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="6dip"
+        android:layout_marginBottom="6dip"
+        android:textAppearance="?android:attr/textAppearanceSmall"
+        android:textColor="?android:attr/textColorSecondary">
+    </TextView>
+
+</LinearLayout>
index 12697ce..f290f38 100644 (file)
@@ -35,5 +35,6 @@
     </string-array>
     <!-- Default query string to search for a print service. -->
     <string name="download_print_service_query">market://search?q=print service</string>
-
+    <!-- Default query string to search for a NFC payment service. -->
+    <string name="download_nfc_payment_service_query">market://search?q=nfc payment</string>
 </resources>
index 370a811..5d86ccf 100644 (file)
     <!-- Title for the prompt if no printers are available and the system is searching for such. [CHAR LIMIT=50] -->
     <string name="print_searching_for_printers">Searching for printers</string>
 
+    <!-- Title for the prompt if no printers are available because the print service is disabled. [CHAR LIMIT=50] -->
+    <string name="print_service_disabled">Service disabled</string>
+
     <!-- Title for the menu item to open the print jobs screen. [CHAR LIMIT=25] -->
     <string name="print_print_jobs">Print jobs</string>
 
-    <!-- Title for the print jobs screen. [CHAR LIMIT=25] -->
-    <string name="print_active_print_jobs">Active print jobs</string>
+    <!-- Title for the print job settings screen. [CHAR LIMIT=25] -->
+    <string name="print_print_job">Print job</string>
+
+    <!-- Title for the button to restart a print job. [CHAR LIMIT=25] -->
+    <string name="print_restart">Restart</string>
+
+    <!-- Title for the button to cancel a print job. [CHAR LIMIT=25] -->
+    <string name="print_cancel">Cancel</string>
+
+    <!-- Template for the summary of a print job. [CHAR LIMIT=25] -->
+    <string name="print_job_summary"><xliff:g id="printer">%1$s</xliff:g>\n<xliff:g id="time">%2$s</xliff:g></string>
+
+    <!-- Template for the label of the state for a ongoing print job. [CHAR LIMIT=25] -->
+    <string name="print_printing_state_title_template">Printing <xliff:g id="print_job_name" example="foo.jpg">%1$s</xliff:g></string>
+
+    <!-- Template for the label of the state for a failed print job. [CHAR LIMIT=25] -->
+    <string name="print_failed_state_title_template">Printer error <xliff:g id="print_job_name" example="foo.jpg">%1$s</xliff:g></string>
+
+    <!-- Template for the label of the state for a blocked print job. [CHAR LIMIT=25] -->
+    <string name="print_blocked_state_title_template">Printer blocked <xliff:g id="print_job_name" example="foo.jpg">%1$s</xliff:g></string>
 
     <!-- App Fuel Gauge strings -->
     <skip />
diff --git a/res/xml/print_job_settings.xml b/res/xml/print_job_settings.xml
new file mode 100644 (file)
index 0000000..a78cec1
--- /dev/null
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 The Android Open Source 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.
+-->
+
+<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:settings="http://schemas.android.com/apk/res/com.android.settings"
+        android:title="@string/print_print_job">
+
+    <Preference
+            android:key="print_job_preference">
+    </Preference>
+
+    <Preference
+            android:key="print_job_message_preference"
+            android:layout="@layout/print_job_summary">
+    </Preference>
+
+</PreferenceScreen>
index dc31968..8a29563 100644 (file)
 <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
         xmlns:settings="http://schemas.android.com/apk/res/com.android.settings"
         android:title="@string/print_settings_title">
+
+    <PreferenceCategory
+            android:key="print_jobs_category"
+            android:title="@string/print_print_jobs"
+            android:order="0">
+    </PreferenceCategory>
+
+    <PreferenceCategory
+            android:key="print_services_category"
+            android:title="@string/print_settings_title"
+            android:order="1">
+    </PreferenceCategory>
+
 </PreferenceScreen>
diff --git a/src/com/android/settings/print/PrintJobSettingsFragment.java b/src/com/android/settings/print/PrintJobSettingsFragment.java
new file mode 100644 (file)
index 0000000..99499c8
--- /dev/null
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 2013 The Android Open Source 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 com.android.settings.print;
+
+import android.app.ActivityManager;
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.preference.Preference;
+import android.print.PrintJob;
+import android.print.PrintJobId;
+import android.print.PrintJobInfo;
+import android.print.PrintManager;
+import android.print.PrintManager.PrintJobStateChangeListener;
+import android.text.TextUtils;
+import android.text.format.DateUtils;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+
+import com.android.settings.R;
+import com.android.settings.SettingsPreferenceFragment;
+
+import java.text.DateFormat;
+
+/**
+ * Fragment for management of a print job.
+ */
+public class PrintJobSettingsFragment extends SettingsPreferenceFragment {
+    private static final int MENU_ITEM_ID_CANCEL = 1;
+    private static final int MENU_ITEM_ID_RESTART = 2;
+
+    private static final String PRINT_JOB_PREFERENCE = "print_job_preference";
+    private static final String PRINT_JOB_MESSAGE_PREFERENCE = "print_job_message_preference";
+
+    private Drawable mListDivider;
+
+    private final PrintJobStateChangeListener mPrintJobStateChangeListener =
+            new PrintJobStateChangeListener() {
+        @Override
+        public void onPrintJobsStateChanged(PrintJobId printJobId) {
+            updateUi();
+        }
+    };
+
+    private PrintManager mPrintManager;
+
+    private Preference mPrintJobPreference;
+    private Preference mMessagePreference;
+
+    private PrintJobId mPrintJobId;
+    private PrintJob mPrintJob;
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        addPreferencesFromResource(R.xml.print_job_settings);
+        mPrintJobPreference = findPreference(PRINT_JOB_PREFERENCE);
+        mMessagePreference = findPreference(PRINT_JOB_MESSAGE_PREFERENCE);
+
+        mPrintManager = ((PrintManager) getActivity().getSystemService(
+                Context.PRINT_SERVICE)).getGlobalPrintManagerForUser(
+                        ActivityManager.getCurrentUser());
+
+        getActivity().getActionBar().setTitle(R.string.print_print_job);
+
+        processArguments();
+
+        setHasOptionsMenu(true);
+    }
+
+    @Override
+    public void onViewCreated(View view, Bundle savedInstanceState) {
+        super.onViewCreated(view, savedInstanceState);
+        getListView().setEnabled(false);
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+        mPrintManager.addPrintJobStateChangeListener(
+                mPrintJobStateChangeListener);
+        updateUi();
+    }
+
+    @Override
+    public void onPause() {
+        super.onPause();
+        mPrintManager.removePrintJobStateChangeListener(
+                mPrintJobStateChangeListener);
+    }
+
+    @Override
+    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+        super.onCreateOptionsMenu(menu, inflater);
+
+        MenuItem cancel = menu.add(0, MENU_ITEM_ID_CANCEL, Menu.NONE,
+                getString(R.string.print_cancel));
+        cancel.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
+
+        if (mPrintJob.isFailed()) {
+            MenuItem restart = menu.add(0, MENU_ITEM_ID_RESTART, Menu.NONE,
+                    getString(R.string.print_restart));
+            restart.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
+        }
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        switch (item.getItemId()) {
+            case MENU_ITEM_ID_CANCEL: {
+                mPrintJob.cancel();
+                finish();
+                return true;
+            }
+
+            case MENU_ITEM_ID_RESTART: {
+                mPrintJob.restart();
+                finish();
+                return true;
+            }
+        }
+
+        return super.onOptionsItemSelected(item);
+    }
+
+    private void processArguments() {
+        mPrintJobId = (PrintJobId) getArguments().getParcelable(
+                PrintSettingsFragment.EXTRA_PRINT_JOB_ID);
+        if (mPrintJobId == null) {
+            finish();
+        }
+    }
+
+    private void updateUi() {
+        mPrintJob = mPrintManager.getPrintJob(mPrintJobId);
+
+        if (mPrintJob == null) {
+            finish();
+        }
+
+        if (mPrintJob.isCancelled() || mPrintJob.isCompleted()) {
+            finish();
+        }
+
+        PrintJobInfo info = mPrintJob.getInfo();
+
+        switch (info.getState()) {
+            case PrintJobInfo.STATE_QUEUED:
+            case PrintJobInfo.STATE_STARTED: {
+                mPrintJobPreference.setTitle(getString(
+                        R.string.print_printing_state_title_template, info.getLabel()));
+            } break;
+
+            case PrintJobInfo.STATE_FAILED: {
+                mPrintJobPreference.setTitle(getString(
+                        R.string.print_failed_state_title_template, info.getLabel()));
+            } break;
+
+            case PrintJobInfo.STATE_BLOCKED: {
+                mPrintJobPreference.setTitle(getString(
+                        R.string.print_blocked_state_title_template, info.getLabel()));
+            } break;
+        }
+
+        mPrintJobPreference.setSummary(getString(R.string.print_job_summary,
+                info.getPrinterName(), DateUtils.formatSameDayTime(
+                        info.getCreationTime(), info.getCreationTime(), DateFormat.SHORT,
+                        DateFormat.SHORT)));
+
+        switch (info.getState()) {
+            case PrintJobInfo.STATE_QUEUED:
+            case PrintJobInfo.STATE_STARTED: {
+                mPrintJobPreference.setIcon(com.android.internal.R.drawable.ic_print);
+            } break;
+
+            case PrintJobInfo.STATE_FAILED:
+            case PrintJobInfo.STATE_BLOCKED: {
+                mPrintJobPreference.setIcon(com.android.internal.R.drawable.ic_print_error);
+            } break;
+        }
+
+        String stateReason = info.getStateReason();
+        if (!TextUtils.isEmpty(stateReason)) {
+            if (getPreferenceScreen().findPreference(PRINT_JOB_MESSAGE_PREFERENCE) == null) {
+                getPreferenceScreen().addPreference(mMessagePreference);
+            }
+            mMessagePreference.setSummary(stateReason);
+            getListView().setDivider(null);
+        } else {
+            getPreferenceScreen().removePreference(mMessagePreference);
+            getListView().setDivider(mListDivider);
+        }
+
+        getActivity().invalidateOptionsMenu();
+    }
+}
index 87db29b..d2d8525 100644 (file)
@@ -27,15 +27,12 @@ import android.content.Context;
 import android.content.DialogInterface;
 import android.content.Intent;
 import android.content.Loader;
-import android.content.pm.ActivityInfo;
 import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
 import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ResolveInfo;
 import android.database.ContentObserver;
 import android.database.DataSetObserver;
 import android.net.Uri;
-import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
 import android.preference.PreferenceActivity;
@@ -54,8 +51,10 @@ import android.view.MenuItem;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.BaseAdapter;
+import android.widget.CompoundButton;
 import android.widget.Filter;
 import android.widget.Filterable;
+import android.widget.ListView;
 import android.widget.SearchView;
 import android.widget.TextView;
 
@@ -69,6 +68,7 @@ import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 
+import android.widget.CompoundButton.OnCheckedChangeListener;
 /**
  * Fragment with print service settings.
  */
@@ -83,7 +83,7 @@ public class PrintServiceSettingsFragment extends SettingsPreferenceFragment
             new SettingsContentObserver(new Handler()) {
         @Override
         public void onChange(boolean selfChange, Uri uri) {
-            updateForServiceEnabledState();
+            updateUiForServiceState();
         }
     };
 
@@ -108,15 +108,15 @@ public class PrintServiceSettingsFragment extends SettingsPreferenceFragment
         }
     };
 
-    protected ToggleSwitch mToggleSwitch;
+    private ToggleSwitch mToggleSwitch;
 
-    protected String mPreferenceKey;
+    private String mPreferenceKey;
 
-    protected CharSequence mSettingsTitle;
-    protected Intent mSettingsIntent;
+    private CharSequence mSettingsTitle;
+    private Intent mSettingsIntent;
 
-    protected CharSequence mAddPrintersTitle;
-    protected Intent mAddPrintersIntent;
+    private CharSequence mAddPrintersTitle;
+    private Intent mAddPrintersIntent;
 
     private CharSequence mEnableWarningTitle;
     private CharSequence mEnableWarningMessage;
@@ -135,9 +135,10 @@ public class PrintServiceSettingsFragment extends SettingsPreferenceFragment
 
     @Override
     public void onResume() {
-        mSettingsContentObserver.register(getContentResolver());
         super.onResume();
-        updateForServiceEnabledState();
+        mSettingsContentObserver.register(getContentResolver());
+        updateEmptyView();
+        updateUiForServiceState();
     }
 
     @Override
@@ -149,12 +150,8 @@ public class PrintServiceSettingsFragment extends SettingsPreferenceFragment
     @Override
     public void onViewCreated(View view, Bundle savedInstanceState) {
         super.onViewCreated(view, savedInstanceState);
-        installActionBarToggleSwitch();
-        processArguments(getArguments());
-        mPrintersAdapter = new PrintersAdapter();
-        mPrintersAdapter.registerDataSetObserver(mDataObserver);
-        getListView().setAdapter(mPrintersAdapter);
-        updateForServiceEnabledState();
+        initComponents();
+        updateUiForArguments();
     }
 
     @Override
@@ -221,7 +218,40 @@ public class PrintServiceSettingsFragment extends SettingsPreferenceFragment
         }
     }
 
-    private void updateForServiceEnabledState() {
+    private void updateEmptyView() {
+        ListView listView = getListView();
+        ViewGroup contentRoot = (ViewGroup) listView.getParent();
+        View emptyView = listView.getEmptyView();
+        if (!mToggleSwitch.isChecked()) {
+            if (emptyView != null
+                    && emptyView.getId() != R.id.empty_printers_list_service_disabled) {
+                contentRoot.removeView(emptyView);
+                emptyView = null;
+            }
+            if (emptyView == null) {
+                emptyView = getActivity().getLayoutInflater().inflate(
+                        R.layout.empty_print_state, contentRoot, false);
+                TextView textView = (TextView) emptyView.findViewById(R.id.message);
+                textView.setText(R.string.print_service_disabled);
+                contentRoot.addView(emptyView);
+                listView.setEmptyView(emptyView);
+            }
+        } else if (mPrintersAdapter.getUnfilteredCount() <= 0) {
+            if (emptyView != null
+                    && emptyView.getId() != R.id.empty_printers_list_service_enabled) {
+                contentRoot.removeView(emptyView);
+                emptyView = null;
+            }
+            if (emptyView == null) {
+                emptyView = getActivity().getLayoutInflater().inflate(
+                        R.layout.empty_printers_list_service_enabled, contentRoot, false);
+                contentRoot.addView(emptyView);
+                listView.setEmptyView(emptyView);
+            }
+        }
+    }
+
+    private void updateUiForServiceState() {
         List<ComponentName> services = SettingsUtils.readEnabledPrintServices(getActivity());
         mServiceEnabled = services.contains(mComponentName);
         if (mServiceEnabled) {
@@ -234,7 +264,10 @@ public class PrintServiceSettingsFragment extends SettingsPreferenceFragment
         getActivity().invalidateOptionsMenu();
     }
 
-    private void installActionBarToggleSwitch() {
+    private void initComponents() {
+        mPrintersAdapter = new PrintersAdapter();
+        mPrintersAdapter.registerDataSetObserver(mDataObserver);
+
         mToggleSwitch = createAndAddActionBarToggleSwitch(getActivity());
         mToggleSwitch.setOnBeforeCheckedChangeListener(new OnBeforeCheckedChangeListener() {
             @Override
@@ -253,9 +286,20 @@ public class PrintServiceSettingsFragment extends SettingsPreferenceFragment
                 return false;
             }
         });
+        mToggleSwitch.setOnCheckedChangeListener(new OnCheckedChangeListener() {
+            @Override
+            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+                updateEmptyView();
+            }
+        });
+
+        getListView().setEnabled(false);
+        getListView().setAdapter(mPrintersAdapter);
     }
 
-    private void processArguments(Bundle arguments) {
+    private void updateUiForArguments() {
+        Bundle arguments = getArguments();
+
         // Key.
         mPreferenceKey = arguments.getString(PrintSettingsFragment.EXTRA_PREFERENCE_KEY);
 
@@ -381,22 +425,21 @@ public class PrintServiceSettingsFragment extends SettingsPreferenceFragment
 
     private static abstract class SettingsContentObserver extends ContentObserver {
 
-    public SettingsContentObserver(Handler handler) {
-        super(handler);
-    }
-
-    public void register(ContentResolver contentResolver) {
-        contentResolver.registerContentObserver(Settings.Secure.getUriFor(
-                Settings.Secure.ENABLED_PRINT_SERVICES), false, this);
-    }
+        public SettingsContentObserver(Handler handler) {
+            super(handler);
+        }
 
-    public void unregister(ContentResolver contentResolver) {
-        contentResolver.unregisterContentObserver(this);
-    }
+        public void register(ContentResolver contentResolver) {
+            contentResolver.registerContentObserver(Settings.Secure.getUriFor(
+                    Settings.Secure.ENABLED_PRINT_SERVICES), false, this);
+        }
 
-    @Override
-    public abstract void onChange(boolean selfChange, Uri uri);
+        public void unregister(ContentResolver contentResolver) {
+            contentResolver.unregisterContentObserver(this);
+        }
 
+        @Override
+        public abstract void onChange(boolean selfChange, Uri uri);
     }
 
     private final class PrintersAdapter extends BaseAdapter
@@ -415,6 +458,7 @@ public class PrintServiceSettingsFragment extends SettingsPreferenceFragment
 
         public void disable() {
             getLoaderManager().destroyLoader(LOADER_ID_PRINTERS_LOADER);
+            mPrinters.clear();
         }
 
         public int getUnfilteredCount() {
@@ -560,7 +604,7 @@ public class PrintServiceSettingsFragment extends SettingsPreferenceFragment
 
         private static final String LOG_TAG = "PrintersLoader";
 
-        private static final boolean DEBUG = true && Build.IS_DEBUGGABLE;
+        private static final boolean DEBUG = false;
 
         private final Map<PrinterId, PrinterInfo> mPrinters =
                 new LinkedHashMap<PrinterId, PrinterInfo>();
index 49f0e65..84865c3 100644 (file)
 
 package com.android.settings.print;
 
+import android.app.ActivityManager;
+import android.app.LoaderManager.LoaderCallbacks;
+import android.content.AsyncTaskLoader;
 import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
+import android.content.Loader;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.database.ContentObserver;
@@ -28,14 +32,23 @@ import android.os.Bundle;
 import android.os.Handler;
 import android.os.Message;
 import android.preference.Preference;
+import android.preference.PreferenceCategory;
 import android.preference.PreferenceScreen;
+import android.print.PrintJob;
+import android.print.PrintJobId;
+import android.print.PrintJobInfo;
+import android.print.PrintManager;
+import android.print.PrintManager.PrintJobStateChangeListener;
 import android.printservice.PrintServiceInfo;
 import android.provider.Settings;
 import android.text.TextUtils;
+import android.text.format.DateUtils;
+import android.util.Log;
 import android.view.Menu;
 import android.view.MenuInflater;
 import android.view.MenuItem;
 import android.view.View;
+import android.view.ViewGroup;
 import android.widget.Switch;
 import android.widget.TextView;
 
@@ -44,6 +57,8 @@ import com.android.settings.DialogCreatable;
 import com.android.settings.R;
 import com.android.settings.SettingsPreferenceFragment;
 
+import java.text.DateFormat;
+import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -53,17 +68,24 @@ public class PrintSettingsFragment extends SettingsPreferenceFragment implements
 
     static final char ENABLED_PRINT_SERVICES_SEPARATOR = ':';
 
+    private static final int LOADER_ID_PRINT_JOBS_LOADER = 1;
+
+    private static final String PRINT_JOBS_CATEGORY = "print_jobs_category";
+    private static final String PRINT_SERVICES_CATEGORY = "print_services_category";
+
     // Extras passed to sub-fragments.
-    static final String EXTRA_PREFERENCE_KEY = "preference_key";
-    static final String EXTRA_CHECKED = "checked";
-    static final String EXTRA_TITLE = "title";
-    static final String EXTRA_ENABLE_WARNING_TITLE = "enable_warning_title";
-    static final String EXTRA_ENABLE_WARNING_MESSAGE = "enable_warning_message";
-    static final String EXTRA_SETTINGS_TITLE = "settings_title";
-    static final String EXTRA_SETTINGS_COMPONENT_NAME = "settings_component_name";
-    static final String EXTRA_ADD_PRINTERS_TITLE = "add_printers_title";
-    static final String EXTRA_ADD_PRINTERS_COMPONENT_NAME = "add_printers_component_name";
-    static final String EXTRA_SERVICE_COMPONENT_NAME = "service_component_name";
+    static final String EXTRA_PREFERENCE_KEY = "EXTRA_PREFERENCE_KEY";
+    static final String EXTRA_CHECKED = "EXTRA_CHECKED";
+    static final String EXTRA_TITLE = "EXTRA_TITLE";
+    static final String EXTRA_ENABLE_WARNING_TITLE = "EXTRA_ENABLE_WARNING_TITLE";
+    static final String EXTRA_ENABLE_WARNING_MESSAGE = "EXTRA_ENABLE_WARNING_MESSAGE";
+    static final String EXTRA_SETTINGS_TITLE = "EXTRA_SETTINGS_TITLE";
+    static final String EXTRA_SETTINGS_COMPONENT_NAME = "EXTRA_SETTINGS_COMPONENT_NAME";
+    static final String EXTRA_ADD_PRINTERS_TITLE = "EXTRA_ADD_PRINTERS_TITLE";
+    static final String EXTRA_ADD_PRINTERS_COMPONENT_NAME = "EXTRA_ADD_PRINTERS_COMPONENT_NAME";
+    static final String EXTRA_SERVICE_COMPONENT_NAME = "EXTRA_SERVICE_COMPONENT_NAME";
+
+    static final String EXTRA_PRINT_JOB_ID = "EXTRA_PRINT_JOB_ID";
 
     private static final String EXTRA_PRINT_SERVICE_COMPONENT_NAME =
             "EXTRA_PRINT_SERVICE_COMPONENT_NAME";
@@ -85,13 +107,27 @@ public class PrintSettingsFragment extends SettingsPreferenceFragment implements
         }
     };
 
-    private Preference mNoServicesMessagePreference;
+    private PreferenceCategory mActivePrintJobsCategory;
+    private PreferenceCategory mPrintServicesCategory;
+
+    private PrintJobsController mPrintJobsController;
+
+    private String mPrintJobPreferenceToActivate;
 
     @Override
     public void onCreate(Bundle icicle) {
         super.onCreate(icicle);
         addPreferencesFromResource(R.xml.print_settings);
-        getActivity().getActionBar().setTitle(R.string.print_settings_title);
+
+        mActivePrintJobsCategory = (PreferenceCategory) findPreference(
+                PRINT_JOBS_CATEGORY);
+        mPrintServicesCategory= (PreferenceCategory) findPreference(
+                PRINT_SERVICES_CATEGORY);
+        getPreferenceScreen().removePreference(mActivePrintJobsCategory);
+
+        mPrintJobsController = new PrintJobsController();
+        getActivity().getLoaderManager().initLoader(LOADER_ID_PRINT_JOBS_LOADER,
+                null, mPrintJobsController);
     }
 
     @Override
@@ -100,8 +136,8 @@ public class PrintSettingsFragment extends SettingsPreferenceFragment implements
         mSettingsPackageMonitor.register(getActivity(), getActivity().getMainLooper(), false);
         mSettingsContentObserver.register(getContentResolver());
         updateServicesPreferences();
-        startPrintServiceSettingsIfNeeded();
         setHasOptionsMenu(true);
+        startSubSettingsIfNeeded();
     }
 
     @Override
@@ -120,10 +156,26 @@ public class PrintSettingsFragment extends SettingsPreferenceFragment implements
                 Uri.parse(getString(R.string.download_print_service_query))));
     }
 
+    @Override
+    public void onViewCreated(View view, Bundle savedInstanceState) {
+        super.onViewCreated(view, savedInstanceState);
+        ViewGroup contentRoot = (ViewGroup) getListView().getParent();
+        View emptyView = getActivity().getLayoutInflater().inflate(
+                    R.layout.empty_print_state, contentRoot, false);
+        TextView textView = (TextView) emptyView.findViewById(R.id.message);
+        textView.setText(R.string.print_no_services_installed);
+        contentRoot.addView(emptyView);
+        getListView().setEmptyView(emptyView);
+    }
+
     private void updateServicesPreferences() {
-        // Since services category is auto generated we have to do a pass
-        // to generate it since services can come and go.
-        getPreferenceScreen().removeAll();
+        if (getPreferenceScreen().findPreference(PRINT_SERVICES_CATEGORY) == null) {
+            getPreferenceScreen().addPreference(mPrintServicesCategory);
+        } else {
+            // Since services category is auto generated we have to do a pass
+            // to generate it since services can come and go.
+            mPrintServicesCategory.removeAll();
+        }
 
         List<ComponentName> enabledServices = SettingsUtils
                 .readEnabledPrintServices(getActivity());
@@ -194,30 +246,15 @@ public class PrintSettingsFragment extends SettingsPreferenceFragment implements
 
             extras.putString(EXTRA_SERVICE_COMPONENT_NAME, componentName.flattenToString());
 
-            getPreferenceScreen().addPreference(preference);
+            mPrintServicesCategory.addPreference(preference);
         }
 
-        if (getPreferenceScreen().getPreferenceCount() == 0) {
-            if (mNoServicesMessagePreference == null) {
-                mNoServicesMessagePreference = new Preference(getActivity()) {
-                    @Override
-                    protected void onBindView(View view) {
-                        super.onBindView(view);
-                        TextView summaryView = (TextView) view.findViewById(R.id.summary);
-                        String title = getString(R.string.print_no_services_installed);
-                        summaryView.setText(title);
-                    }
-                };
-                mNoServicesMessagePreference.setPersistent(false);
-                mNoServicesMessagePreference.setLayoutResource(
-                        R.layout.text_description_preference);
-                mNoServicesMessagePreference.setSelectable(false);
-            }
-            getPreferenceScreen().addPreference(mNoServicesMessagePreference);
+        if (mPrintServicesCategory.getPreferenceCount() == 0) {
+            getPreferenceScreen().removePreference(mPrintServicesCategory);
         }
     }
 
-    private void startPrintServiceSettingsIfNeeded() {
+    private void startSubSettingsIfNeeded() {
         if (getArguments() == null) {
             return;
         }
@@ -228,6 +265,19 @@ public class PrintSettingsFragment extends SettingsPreferenceFragment implements
             if (prereference != null) {
                 prereference.performClick(getPreferenceScreen());
             }
+        } else {
+            String printJobId = getArguments().getString(EXTRA_PRINT_JOB_ID);
+            if (printJobId != null) {
+                getArguments().remove(EXTRA_PRINT_JOB_ID);
+                Preference preference = findPreference(printJobId);
+                if (preference != null) {
+                    preference.performClick(getPreferenceScreen());
+                } else {
+                    // The preference not being present may mean the the print job
+                    // loader has not completed so make a note and wait for the load.
+                    mPrintJobPreferenceToActivate = printJobId;
+                }
+            }
         }
     }
 
@@ -301,4 +351,207 @@ public class PrintSettingsFragment extends SettingsPreferenceFragment implements
         @Override
         public abstract void onChange(boolean selfChange, Uri uri);
     }
+
+    private final class PrintJobsController implements LoaderCallbacks<List<PrintJobInfo>> {
+
+        @Override
+        public Loader<List<PrintJobInfo>> onCreateLoader(int id, Bundle args) {
+            if (id == LOADER_ID_PRINT_JOBS_LOADER) {
+                return new PrintJobsLoader(getActivity());
+            }
+            return null;
+        }
+
+        @Override
+        public void onLoadFinished(Loader<List<PrintJobInfo>> loader,
+                List<PrintJobInfo> printJobs) {
+            if (printJobs == null || printJobs.isEmpty()) {
+                getPreferenceScreen().removePreference(mActivePrintJobsCategory);
+            } else {
+                if (getPreferenceScreen().findPreference(PRINT_JOBS_CATEGORY) == null) {
+                    getPreferenceScreen().addPreference(mActivePrintJobsCategory);
+                }
+
+                mActivePrintJobsCategory.removeAll();
+
+                final int printJobCount = printJobs.size();
+                for (int i = 0; i < printJobCount; i++) {
+                    PrintJobInfo printJob = printJobs.get(i);
+
+                    PreferenceScreen preference = getPreferenceManager()
+                            .createPreferenceScreen(getActivity());
+
+                    preference.setPersistent(false);
+                    preference.setFragment(PrintJobSettingsFragment.class.getName());
+                    preference.setKey(printJob.getId().flattenToString());
+
+                    switch (printJob.getState()) {
+                        case PrintJobInfo.STATE_QUEUED:
+                        case PrintJobInfo.STATE_STARTED: {
+                            preference.setTitle(getString(
+                                    R.string.print_printing_state_title_template,
+                                    printJob.getLabel()));
+                        } break;
+
+                        case PrintJobInfo.STATE_FAILED: {
+                            preference.setTitle(getString(
+                                    R.string.print_failed_state_title_template,
+                                    printJob.getLabel()));
+                        } break;
+
+                        case PrintJobInfo.STATE_BLOCKED: {
+                            preference.setTitle(getString(
+                                    R.string.print_blocked_state_title_template,
+                                    printJob.getLabel()));
+                        } break;
+                    }
+
+                    preference.setSummary(getString(R.string.print_job_summary,
+                            printJob.getPrinterName(), DateUtils.formatSameDayTime(
+                                    printJob.getCreationTime(), printJob.getCreationTime(),
+                                    DateFormat.SHORT, DateFormat.SHORT)));
+
+                    switch (printJob.getState()) {
+                        case PrintJobInfo.STATE_QUEUED:
+                        case PrintJobInfo.STATE_STARTED: {
+                            preference.setIcon(com.android.internal.R.drawable.ic_print);
+                        } break;
+
+                        case PrintJobInfo.STATE_FAILED:
+                        case PrintJobInfo.STATE_BLOCKED: {
+                            preference.setIcon(com.android.internal.R.drawable.ic_print_error);
+                        } break;
+                    }
+
+                    Bundle extras = preference.getExtras();
+                    extras.putParcelable(EXTRA_PRINT_JOB_ID, printJob.getId());
+
+                    mActivePrintJobsCategory.addPreference(preference);
+                }
+
+                // If were waiting for creating a preference for a print
+                // job so we can start it - do that.
+                if (mPrintJobPreferenceToActivate != null) {
+                    Preference preference = findPreference(mPrintJobPreferenceToActivate);
+                    mPrintJobPreferenceToActivate = null;
+                    if (preference != null) {
+                        preference.performClick(getPreferenceScreen());
+                    }
+                }
+            }
+        }
+
+        @Override
+        public void onLoaderReset(Loader<List<PrintJobInfo>> loader) {
+            getPreferenceScreen().removePreference(mActivePrintJobsCategory);
+        }
+    }
+
+    private static final class PrintJobsLoader extends AsyncTaskLoader<List<PrintJobInfo>> {
+
+        private static final String LOG_TAG = "PrintJobsLoader";
+
+        private static final boolean DEBUG = true;
+
+        private List <PrintJobInfo> mPrintJobs = new ArrayList<PrintJobInfo>();
+
+        private final PrintManager mPrintManager;
+
+        private PrintJobStateChangeListener mPrintJobStateChangeListener;
+
+        public PrintJobsLoader(Context context) {
+            super(context);
+            mPrintManager = ((PrintManager) context.getSystemService(
+                    Context.PRINT_SERVICE)).getGlobalPrintManagerForUser(
+                            ActivityManager.getCurrentUser());
+        }
+
+        @Override
+        public void deliverResult(List<PrintJobInfo> printJobs) {
+            if (isStarted()) {
+                super.deliverResult(printJobs);
+            }
+        }
+
+        @Override
+        protected void onStartLoading() {
+            if (DEBUG) {
+                Log.i(LOG_TAG, "onStartLoading()");
+            }
+            // If we already have a result, deliver it immediately.
+            if (!mPrintJobs.isEmpty()) {
+                deliverResult(new ArrayList<PrintJobInfo>(mPrintJobs));
+            }
+            // Start watching for changes.
+            if (mPrintJobStateChangeListener == null) {
+                mPrintJobStateChangeListener = new PrintJobStateChangeListener() {
+                    @Override
+                    public void onPrintJobsStateChanged(PrintJobId printJobId) {
+                        onForceLoad();
+                    }
+                };
+                mPrintManager.addPrintJobStateChangeListener(
+                        mPrintJobStateChangeListener);
+            }
+            // If the data changed or we have no data - load it now.
+            if (mPrintJobs.isEmpty()) {
+                onForceLoad();
+            }
+        }
+
+        @Override
+        protected void onStopLoading() {
+            if (DEBUG) {
+                Log.i(LOG_TAG, "onStopLoading()");
+            }
+            // Cancel the load in progress if possible.
+            onCancelLoad();
+        }
+
+        @Override
+        protected void onReset() {
+            if (DEBUG) {
+                Log.i(LOG_TAG, "onReset()");
+            }
+            // Stop loading.
+            onStopLoading();
+            // Clear the cached result.
+            mPrintJobs.clear();
+            // Stop watching for changes.
+            if (mPrintJobStateChangeListener != null) {
+                mPrintManager.removePrintJobStateChangeListener(
+                        mPrintJobStateChangeListener);
+                mPrintJobStateChangeListener = null;
+            }
+        }
+
+        @Override
+        public List<PrintJobInfo> loadInBackground() {
+            List<PrintJobInfo> printJobInfos = null;
+            List<PrintJob> printJobs = mPrintManager.getPrintJobs();
+            final int printJobCount = printJobs.size();
+            for (int i = 0; i < printJobCount; i++) {
+                PrintJobInfo printJob = printJobs.get(i).getInfo();
+                if (shouldShowToUser(printJob)) {
+                    if (printJobInfos == null) {
+                        printJobInfos = new ArrayList<PrintJobInfo>();
+                    }
+                    printJobInfos.add(printJob);
+                }
+            }
+            return printJobInfos;
+        }
+
+        private static boolean shouldShowToUser(PrintJobInfo printJob) {
+            switch (printJob.getState()) {
+                case PrintJobInfo.STATE_QUEUED:
+                case PrintJobInfo.STATE_STARTED:
+                case PrintJobInfo.STATE_BLOCKED:
+                case PrintJobInfo.STATE_FAILED: {
+                    return true;
+                }
+            }
+            return false;
+        }
+    }
 }