Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 23757527 authored by Svetoslav Ganov's avatar Svetoslav Ganov Committed by Android (Google) Code Review
Browse files

Merge "Hide the print dialog if the printing activity is destroyed." into klp-dev

parents 96844ed8 858a1850
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -165,6 +165,7 @@ LOCAL_SRC_FILES += \
	core/java/android/print/ILayoutResultCallback.aidl \
	core/java/android/print/IPrinterDiscoveryObserver.aidl \
	core/java/android/print/IPrintDocumentAdapter.aidl \
	core/java/android/print/IPrintDocumentAdapterObserver.aidl \
	core/java/android/print/IPrintJobStateChangeListener.aidl \
	core/java/android/print/IPrintManager.aidl \
	core/java/android/print/IPrintSpooler.aidl \
+2 −0
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package android.print;
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
import android.print.ILayoutResultCallback;
import android.print.IPrintDocumentAdapterObserver;
import android.print.IWriteResultCallback;
import android.print.PageRange;
import android.print.PrintAttributes;
@@ -29,6 +30,7 @@ import android.print.PrintAttributes;
 * @hide
 */
oneway interface IPrintDocumentAdapter {
    void setObserver(in IPrintDocumentAdapterObserver observer);
    void start();
    void layout(in PrintAttributes oldAttributes, in PrintAttributes newAttributes,
            ILayoutResultCallback callback, in Bundle metadata, int sequence);
+26 −0
Original line number Diff line number Diff line
/*
 * 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 android.print;

/**
 * Interface for observing the state of a print document adapter.
 *
 * @hide
 */
oneway interface IPrintDocumentAdapterObserver {
    void onDestroy();
}
+198 −71
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

package android.print;

import android.app.Activity;
import android.app.Application.ActivityLifecycleCallbacks;
import android.content.Context;
import android.content.IntentSender;
import android.content.IntentSender.SendIntentException;
@@ -302,8 +304,8 @@ public final class PrintManager {
        if (TextUtils.isEmpty(printJobName)) {
            throw new IllegalArgumentException("priintJobName cannot be empty");
        }
        PrintDocumentAdapterDelegate delegate = new PrintDocumentAdapterDelegate(documentAdapter,
                mContext.getMainLooper());
        PrintDocumentAdapterDelegate delegate = new PrintDocumentAdapterDelegate(
                mContext, documentAdapter);
        try {
            Bundle result = mService.print(printJobName, delegate,
                    attributes, mContext.getPackageName(), mAppId, mUserId);
@@ -369,17 +371,21 @@ public final class PrintManager {
        return new PrinterDiscoverySession(mService, mContext, mUserId);
    }

    private static final class PrintDocumentAdapterDelegate extends IPrintDocumentAdapter.Stub {
    private static final class PrintDocumentAdapterDelegate extends IPrintDocumentAdapter.Stub
            implements ActivityLifecycleCallbacks {

        private final Object mLock = new Object();

        private CancellationSignal mLayoutOrWriteCancellation;

        private PrintDocumentAdapter mDocumentAdapter; // Strong reference OK -
                                                       // cleared in finish()
        private Activity mActivity; // Strong reference OK - cleared in finish()

        private PrintDocumentAdapter mDocumentAdapter; // Strong reference OK - cleared in finish

        private Handler mHandler; // Strong reference OK - cleared in finish()

        private IPrintDocumentAdapterObserver mObserver; // Strong reference OK - cleared in finish

        private LayoutSpec mLastLayoutSpec;

        private WriteSpec mLastWriteSpec;
@@ -390,16 +396,42 @@ public final class PrintManager {
        private boolean mFinishRequested;
        private boolean mFinished;

        public PrintDocumentAdapterDelegate(PrintDocumentAdapter documentAdapter, Looper looper) {
        private boolean mDestroyed;

        public PrintDocumentAdapterDelegate(Context context,
                PrintDocumentAdapter documentAdapter) {
            if (!(context instanceof Activity)) {
                throw new IllegalStateException("Can print only from an activity");
            }
            mActivity = (Activity) context;
            mDocumentAdapter = documentAdapter;
            mHandler = new MyHandler(looper);
            mHandler = new MyHandler(mActivity.getMainLooper());
            mActivity.getApplication().registerActivityLifecycleCallbacks(this);
        }

        @Override
        public void setObserver(IPrintDocumentAdapterObserver observer) {
            final boolean destroyed;
            synchronized (mLock) {
                if (!mDestroyed) {
                    mObserver = observer;
                }
                destroyed = mDestroyed;
            }
            if (destroyed) {
                try {
                    observer.onDestroy();
                } catch (RemoteException re) {
                    Log.e(LOG_TAG, "Error announcing destroyed state", re);
                }
            }
        }

        @Override
        public void start() {
            synchronized (mLock) {
                // Started or finished - nothing to do.
                if (mStartReqeusted || mFinishRequested) {
                // Started called or finish called or destroyed - nothing to do.
                if (mStartReqeusted || mFinishRequested || mDestroyed) {
                    return;
                }

@@ -412,12 +444,11 @@ public final class PrintManager {
        @Override
        public void layout(PrintAttributes oldAttributes, PrintAttributes newAttributes,
                ILayoutResultCallback callback, Bundle metadata, int sequence) {
            final boolean destroyed;
            synchronized (mLock) {
                // Start not called or finish called - nothing to do.
                if (!mStartReqeusted || mFinishRequested) {
                    return;
                }

                destroyed = mDestroyed;
                // If start called and not finished called and not destroyed - do some work.
                if (mStartReqeusted && !mFinishRequested && !mDestroyed) {
                    // Layout cancels write and overrides layout.
                    if (mLastWriteSpec != null) {
                        IoUtils.closeQuietly(mLastWriteSpec.fd);
@@ -440,16 +471,23 @@ public final class PrintManager {
                    doPendingWorkLocked();
                }
            }
            if (destroyed) {
                try {
                    callback.onLayoutFailed(null, sequence);
                } catch (RemoteException re) {
                    Log.i(LOG_TAG, "Error notifying for cancelled layout", re);
                }
            }
        }

        @Override
        public void write(PageRange[] pages, ParcelFileDescriptor fd,
                IWriteResultCallback callback, int sequence) {
            final boolean destroyed;
            synchronized (mLock) {
                // Start not called or finish called - nothing to do.
                if (!mStartReqeusted || mFinishRequested) {
                    return;
                }

                destroyed = mDestroyed;
                // If start called and not finished called and not destroyed - do some work.
                if (mStartReqeusted && !mFinishRequested && !mDestroyed) {
                    // Write cancels previous writes.
                    if (mLastWriteSpec != null) {
                        IoUtils.closeQuietly(mLastWriteSpec.fd);
@@ -471,12 +509,20 @@ public final class PrintManager {
                    doPendingWorkLocked();
                }
            }
            if (destroyed) {
                try {
                    callback.onWriteFailed(null, sequence);
                } catch (RemoteException re) {
                    Log.i(LOG_TAG, "Error notifying for cancelled write", re);
                }
            }
        }

        @Override
        public void finish() {
            synchronized (mLock) {
                // Start not called or finish called - nothing to do.
                if (!mStartReqeusted || mFinishRequested) {
                // Start not called or finish called or destroyed - nothing to do.
                if (!mStartReqeusted || mFinishRequested || mDestroyed) {
                    return;
                }

@@ -495,15 +541,78 @@ public final class PrintManager {
            }
        }

        @Override
        public void onActivityPaused(Activity activity) {
            /* do nothing */
        }

        @Override
        public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
            /* do nothing */
        }

        @Override
        public void onActivityStarted(Activity activity) {
            /* do nothing */
        }

        @Override
        public void onActivityResumed(Activity activity) {
            /* do nothing */
        }

        @Override
        public void onActivityStopped(Activity activity) {
            /* do nothing */
        }

        @Override
        public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
            /* do nothing */
        }

        @Override
        public void onActivityDestroyed(Activity activity) {
            // We really care only if the activity is being destroyed to
            // notify the the print spooler so it can close the print dialog.
            // Note the the spooler has a death recipient that observes if
            // this process gets killed so we cover the case of onDestroy not
            // being called due to this process being killed to reclaim memory.
            final IPrintDocumentAdapterObserver observer;
            synchronized (mLock) {
                if (activity == mActivity) {
                    mDestroyed = true;
                    observer = mObserver;
                    clearLocked();
                } else {
                    observer = null;
                    activity = null;
                }
            }
            if (observer != null) {
                activity.getApplication().unregisterActivityLifecycleCallbacks(
                        PrintDocumentAdapterDelegate.this);
                try {
                    observer.onDestroy();
                } catch (RemoteException re) {
                    Log.e(LOG_TAG, "Error announcing destroyed state", re);
                }
            }
        }

        private boolean isFinished() {
            return mDocumentAdapter == null;
        }

        private void doFinish() {
        private void clearLocked() {
            mActivity = null;
            mDocumentAdapter = null;
            mHandler = null;
            synchronized (mLock) {
            mLayoutOrWriteCancellation = null;
            mLastLayoutSpec = null;
            if (mLastWriteSpec != null) {
                IoUtils.closeQuietly(mLastWriteSpec.fd);
                mLastWriteSpec = null;
            }
        }

@@ -564,63 +673,81 @@ public final class PrintManager {
                }
                switch (message.what) {
                    case MSG_START: {
                        mDocumentAdapter.onStart();
                        final PrintDocumentAdapter adapter;
                        synchronized (mLock) {
                            adapter = mDocumentAdapter;
                        }
                        break;
                        if (adapter != null) {
                            adapter.onStart();
                        }
                    } break;

                    case MSG_LAYOUT: {
                        final PrintDocumentAdapter adapter;
                        final CancellationSignal cancellation;
                        final LayoutSpec layoutSpec;

                        synchronized (mLock) {
                            adapter = mDocumentAdapter;
                            layoutSpec = mLastLayoutSpec;
                            mLastLayoutSpec = null;
                            cancellation = new CancellationSignal();
                            mLayoutOrWriteCancellation = cancellation;
                        }

                        if (layoutSpec != null) {
                        if (layoutSpec != null && adapter != null) {
                            if (DEBUG) {
                                Log.i(LOG_TAG, "Performing layout");
                            }
                            mDocumentAdapter.onLayout(layoutSpec.oldAttributes,
                            adapter.onLayout(layoutSpec.oldAttributes,
                                    layoutSpec.newAttributes, cancellation,
                                    new MyLayoutResultCallback(layoutSpec.callback,
                                            layoutSpec.sequence), layoutSpec.metadata);
                        }
                    }
                        break;
                    } break;

                    case MSG_WRITE: {
                        final PrintDocumentAdapter adapter;
                        final CancellationSignal cancellation;
                        final WriteSpec writeSpec;

                        synchronized (mLock) {
                            adapter = mDocumentAdapter;
                            writeSpec = mLastWriteSpec;
                            mLastWriteSpec = null;
                            cancellation = new CancellationSignal();
                            mLayoutOrWriteCancellation = cancellation;
                        }

                        if (writeSpec != null) {
                        if (writeSpec != null && adapter != null) {
                            if (DEBUG) {
                                Log.i(LOG_TAG, "Performing write");
                            }
                            mDocumentAdapter.onWrite(writeSpec.pages, writeSpec.fd,
                            adapter.onWrite(writeSpec.pages, writeSpec.fd,
                                    cancellation, new MyWriteResultCallback(writeSpec.callback,
                                            writeSpec.fd, writeSpec.sequence));
                        }
                    }
                        break;
                    } break;

                    case MSG_FINISH: {
                        if (DEBUG) {
                            Log.i(LOG_TAG, "Performing finish");
                        }
                        mDocumentAdapter.onFinish();
                        doFinish();
                        final PrintDocumentAdapter adapter;
                        final Activity activity;
                        synchronized (mLock) {
                            adapter = mDocumentAdapter;
                            activity = mActivity;
                            clearLocked();
                        }
                        if (adapter != null) {
                            adapter.onFinish();
                        }
                        break;
                        if (activity != null) {
                            activity.getApplication().unregisterActivityLifecycleCallbacks(
                                    PrintDocumentAdapterDelegate.this);
                        }
                    } break;

                    default: {
                        throw new IllegalArgumentException("Unknown message: "
+56 −15
Original line number Diff line number Diff line
@@ -40,6 +40,7 @@ import android.os.Message;
import android.os.RemoteException;
import android.print.ILayoutResultCallback;
import android.print.IPrintDocumentAdapter;
import android.print.IPrintDocumentAdapterObserver;
import android.print.IWriteResultCallback;
import android.print.PageRange;
import android.print.PrintAttributes;
@@ -201,6 +202,14 @@ public class PrintJobConfigActivity extends Activity {
            throw new IllegalArgumentException("PrintDocumentAdapter cannot be null");
        }

        try {
            IPrintDocumentAdapter.Stub.asInterface(mIPrintDocumentAdapter)
                    .setObserver(new PrintDocumentAdapterObserver(this));
        } catch (RemoteException re) {
            finish();
            return;
        }

        PrintAttributes attributes = printJob.getAttributes();
        if (attributes != null) {
            mCurrPrintAttributes.copyFrom(attributes);
@@ -249,27 +258,29 @@ public class PrintJobConfigActivity extends Activity {
        // We can safely do the work in here since at this point
        // the system is bound to our (spooler) process which
        // guarantees that this process will not be killed.
        if (mController.hasStarted()) {
        if (mController != null && mController.hasStarted()) {
            mController.finish();
        }
        if (mEditor.isPrintConfirmed() && mController.isFinished()) {
        if (mEditor != null && mEditor.isPrintConfirmed()
                && mController != null && mController.isFinished()) {
                mSpoolerProvider.getSpooler().setPrintJobState(mPrintJobId,
                        PrintJobInfo.STATE_QUEUED, null);
        } else {
            mSpoolerProvider.getSpooler().setPrintJobState(mPrintJobId,
                    PrintJobInfo.STATE_CANCELED, null);
        }
        mIPrintDocumentAdapter.unlinkToDeath(mDeathRecipient, 0);
        if (mGeneratingPrintJobDialog != null) {
            mGeneratingPrintJobDialog.dismiss();
            mGeneratingPrintJobDialog = null;
        }
        mIPrintDocumentAdapter.unlinkToDeath(mDeathRecipient, 0);
        mSpoolerProvider.destroy();
        super.onDestroy();
    }

    public boolean onTouchEvent(MotionEvent event) {
        if (!mEditor.isPrintConfirmed() && mEditor.shouldCloseOnTouch(event)) {
        if (mController != null && mEditor != null &&
                !mEditor.isPrintConfirmed() && mEditor.shouldCloseOnTouch(event)) {
            if (!mController.isWorking()) {
                PrintJobConfigActivity.this.finish();
            }
@@ -287,6 +298,7 @@ public class PrintJobConfigActivity extends Activity {
    }

    public boolean onKeyUp(int keyCode, KeyEvent event) {
        if (mController != null && mEditor != null) {
            if (keyCode == KeyEvent.KEYCODE_BACK) {
                if (mEditor.isShwoingGeneratingPrintJobUi()) {
                    return true;
@@ -299,6 +311,7 @@ public class PrintJobConfigActivity extends Activity {
                mEditor.cancel();
                return true;
            }
        }
        return super.onKeyUp(keyCode, event);
    }

@@ -2701,4 +2714,32 @@ public class PrintJobConfigActivity extends Activity {
            /* do noting - we are in the same process */
        }
    }

    private static final class PrintDocumentAdapterObserver
            extends IPrintDocumentAdapterObserver.Stub {
        private final WeakReference<PrintJobConfigActivity> mWeakActvity;

        public PrintDocumentAdapterObserver(PrintJobConfigActivity activity) {
            mWeakActvity = new WeakReference<PrintJobConfigActivity>(activity);
        }

        @Override
        public void onDestroy() {
            final PrintJobConfigActivity activity = mWeakActvity.get();
            if (activity != null) {
                activity.mController.mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        if (activity.mController != null) {
                            activity.mController.cancel();
                        }
                        if (activity.mEditor != null) {
                            activity.mEditor.cancel();
                        }
                        activity.finish();
                    }
                });
            }
        }
    }
}