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

Commit e9ffeac1 authored by Svetoslav Ganov's avatar Svetoslav Ganov Committed by Android Git Automerger
Browse files

am 8a51e2f4: am a53e1f81: am 23757527: Merge "Hide the print dialog if the...

am 8a51e2f4: am a53e1f81: am 23757527: Merge "Hide the print dialog if the printing activity is destroyed." into klp-dev

* commit '8a51e2f4':
  Hide the print dialog if the printing activity is destroyed.
parents 200223cd 8a51e2f4
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -169,6 +169,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();
                    }
                });
            }
        }
    }
}