void detach() {
      if (mDestroyed) {
        return;
      }

      mDestroyed = true;

      if (mVisible) {
        mVisible = false;
        if (DEBUG) Log.v(TAG, "onVisibilityChanged(false): " + this);
        onVisibilityChanged(false);
      }

      reportSurfaceDestroyed();

      if (DEBUG) Log.v(TAG, "onDestroy(): " + this);
      onDestroy();

      unregisterReceiver(mReceiver);

      if (mCreated) {
        try {
          if (DEBUG)
            Log.v(
                TAG,
                "Removing window and destroying surface "
                    + mSurfaceHolder.getSurface()
                    + " of: "
                    + this);

          if (mInputEventReceiver != null) {
            mInputEventReceiver.dispose();
            mInputEventReceiver = null;
          }

          mSession.remove(mWindow);
        } catch (RemoteException e) {
        }
        mSurfaceHolder.mSurface.release();
        mCreated = false;

        // Dispose the input channel after removing the window so the Window Manager
        // doesn't interpret the input channel being closed as an abnormal termination.
        if (mInputChannel != null) {
          mInputChannel.dispose();
          mInputChannel = null;
        }
      }
    }
 @Override
 public void resized(
     Rect frame,
     Rect overscanInsets,
     Rect contentInsets,
     Rect visibleInsets,
     boolean reportDraw,
     Configuration newConfig) {
   if (reportDraw) {
     try {
       mSession.finishDrawing(this);
     } catch (RemoteException e) {
     }
   }
 }
 void doCommand(WallpaperCommand cmd) {
   Bundle result;
   if (!mDestroyed) {
     result = onCommand(cmd.action, cmd.x, cmd.y, cmd.z, cmd.extras, cmd.sync);
   } else {
     result = null;
   }
   if (cmd.sync) {
     try {
       if (DEBUG) Log.v(TAG, "Reporting command complete");
       mSession.wallpaperCommandComplete(mWindow.asBinder(), result);
     } catch (RemoteException e) {
     }
   }
 }
    void doOffsetsChanged(boolean always) {
      if (mDestroyed) {
        return;
      }

      if (!always && !mOffsetsChanged) {
        return;
      }

      float xOffset;
      float yOffset;
      float xOffsetStep;
      float yOffsetStep;
      boolean sync;
      synchronized (mLock) {
        xOffset = mPendingXOffset;
        yOffset = mPendingYOffset;
        xOffsetStep = mPendingXOffsetStep;
        yOffsetStep = mPendingYOffsetStep;
        sync = mPendingSync;
        mPendingSync = false;
        mOffsetMessageEnqueued = false;
      }

      if (mSurfaceCreated) {
        if (mReportedVisible) {
          if (DEBUG) Log.v(TAG, "Offsets change in " + this + ": " + xOffset + "," + yOffset);
          final int availw = mIWallpaperEngine.mReqWidth - mCurWidth;
          final int xPixels = availw > 0 ? -(int) (availw * xOffset + .5f) : 0;
          final int availh = mIWallpaperEngine.mReqHeight - mCurHeight;
          final int yPixels = availh > 0 ? -(int) (availh * yOffset + .5f) : 0;
          onOffsetsChanged(xOffset, yOffset, xOffsetStep, yOffsetStep, xPixels, yPixels);
        } else {
          mOffsetsChanged = true;
        }
      }

      if (sync) {
        try {
          if (DEBUG) Log.v(TAG, "Reporting offsets change complete");
          mSession.wallpaperOffsetsComplete(mWindow.asBinder());
        } catch (RemoteException e) {
        }
      }
    }
    void updateSurface(boolean forceRelayout, boolean forceReport, boolean redrawNeeded) {
      if (mDestroyed) {
        Log.w(TAG, "Ignoring updateSurface: destroyed");
      }

      int myWidth = mSurfaceHolder.getRequestedWidth();
      if (myWidth <= 0) myWidth = ViewGroup.LayoutParams.MATCH_PARENT;
      int myHeight = mSurfaceHolder.getRequestedHeight();
      if (myHeight <= 0) myHeight = ViewGroup.LayoutParams.MATCH_PARENT;

      final boolean creating = !mCreated;
      final boolean surfaceCreating = !mSurfaceCreated;
      final boolean formatChanged = mFormat != mSurfaceHolder.getRequestedFormat();
      boolean sizeChanged = mWidth != myWidth || mHeight != myHeight;
      final boolean typeChanged = mType != mSurfaceHolder.getRequestedType();
      final boolean flagsChanged =
          mCurWindowFlags != mWindowFlags || mCurWindowPrivateFlags != mWindowPrivateFlags;
      if (forceRelayout
          || creating
          || surfaceCreating
          || formatChanged
          || sizeChanged
          || typeChanged
          || flagsChanged
          || redrawNeeded
          || !mIWallpaperEngine.mShownReported) {

        if (DEBUG)
          Log.v(
              TAG,
              "Changes: creating="
                  + creating
                  + " format="
                  + formatChanged
                  + " size="
                  + sizeChanged);

        try {
          mWidth = myWidth;
          mHeight = myHeight;
          mFormat = mSurfaceHolder.getRequestedFormat();
          mType = mSurfaceHolder.getRequestedType();

          mLayout.x = 0;
          mLayout.y = 0;
          mLayout.width = myWidth;
          mLayout.height = myHeight;

          mLayout.format = mFormat;

          mCurWindowFlags = mWindowFlags;
          mLayout.flags =
              mWindowFlags
                  | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
                  | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
                  | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
          mCurWindowPrivateFlags = mWindowPrivateFlags;
          mLayout.privateFlags = mWindowPrivateFlags;

          mLayout.memoryType = mType;
          mLayout.token = mWindowToken;

          if (!mCreated) {
            mLayout.type = mIWallpaperEngine.mWindowType;
            mLayout.gravity = Gravity.START | Gravity.TOP;
            mLayout.setTitle(WallpaperService.this.getClass().getName());
            mLayout.windowAnimations = com.android.internal.R.style.Animation_Wallpaper;
            mInputChannel = new InputChannel();
            if (mSession.addToDisplay(
                    mWindow,
                    mWindow.mSeq,
                    mLayout,
                    View.VISIBLE,
                    Display.DEFAULT_DISPLAY,
                    mContentInsets,
                    mInputChannel)
                < 0) {
              Log.w(TAG, "Failed to add window while updating wallpaper surface.");
              return;
            }
            mCreated = true;

            mInputEventReceiver = new WallpaperInputEventReceiver(mInputChannel, Looper.myLooper());
          }

          mSurfaceHolder.mSurfaceLock.lock();
          mDrawingAllowed = true;

          final int relayoutResult =
              mSession.relayout(
                  mWindow,
                  mWindow.mSeq,
                  mLayout,
                  mWidth,
                  mHeight,
                  View.VISIBLE,
                  0,
                  mWinFrame,
                  mContentInsets,
                  mVisibleInsets,
                  mConfiguration,
                  mSurfaceHolder.mSurface);

          if (DEBUG) Log.v(TAG, "New surface: " + mSurfaceHolder.mSurface + ", frame=" + mWinFrame);

          int w = mWinFrame.width();
          if (mCurWidth != w) {
            sizeChanged = true;
            mCurWidth = w;
          }
          int h = mWinFrame.height();
          if (mCurHeight != h) {
            sizeChanged = true;
            mCurHeight = h;
          }

          mSurfaceHolder.setSurfaceFrameSize(w, h);
          mSurfaceHolder.mSurfaceLock.unlock();

          if (!mSurfaceHolder.mSurface.isValid()) {
            reportSurfaceDestroyed();
            if (DEBUG) Log.v(TAG, "Layout: Surface destroyed");
            return;
          }

          boolean didSurface = false;

          try {
            mSurfaceHolder.ungetCallbacks();

            if (surfaceCreating) {
              mIsCreating = true;
              didSurface = true;
              if (DEBUG) Log.v(TAG, "onSurfaceCreated(" + mSurfaceHolder + "): " + this);
              onSurfaceCreated(mSurfaceHolder);
              SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
              if (callbacks != null) {
                for (SurfaceHolder.Callback c : callbacks) {
                  c.surfaceCreated(mSurfaceHolder);
                }
              }
            }

            redrawNeeded |=
                creating || (relayoutResult & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0;

            if (forceReport || creating || surfaceCreating || formatChanged || sizeChanged) {
              if (DEBUG) {
                RuntimeException e = new RuntimeException();
                e.fillInStackTrace();
                Log.w(
                    TAG,
                    "forceReport="
                        + forceReport
                        + " creating="
                        + creating
                        + " formatChanged="
                        + formatChanged
                        + " sizeChanged="
                        + sizeChanged,
                    e);
              }
              if (DEBUG)
                Log.v(
                    TAG,
                    "onSurfaceChanged("
                        + mSurfaceHolder
                        + ", "
                        + mFormat
                        + ", "
                        + mCurWidth
                        + ", "
                        + mCurHeight
                        + "): "
                        + this);
              didSurface = true;
              onSurfaceChanged(mSurfaceHolder, mFormat, mCurWidth, mCurHeight);
              SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
              if (callbacks != null) {
                for (SurfaceHolder.Callback c : callbacks) {
                  c.surfaceChanged(mSurfaceHolder, mFormat, mCurWidth, mCurHeight);
                }
              }
            }

            if (redrawNeeded) {
              onSurfaceRedrawNeeded(mSurfaceHolder);
              SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
              if (callbacks != null) {
                for (SurfaceHolder.Callback c : callbacks) {
                  if (c instanceof SurfaceHolder.Callback2) {
                    ((SurfaceHolder.Callback2) c).surfaceRedrawNeeded(mSurfaceHolder);
                  }
                }
              }
            }

            if (didSurface && !mReportedVisible) {
              // This wallpaper is currently invisible, but its
              // surface has changed.  At this point let's tell it
              // again that it is invisible in case the report about
              // the surface caused it to start running.  We really
              // don't want wallpapers running when not visible.
              if (mIsCreating) {
                // Some wallpapers will ignore this call if they
                // had previously been told they were invisble,
                // so if we are creating a new surface then toggle
                // the state to get them to notice.
                if (DEBUG) Log.v(TAG, "onVisibilityChanged(true) at surface: " + this);
                onVisibilityChanged(true);
              }
              if (DEBUG) Log.v(TAG, "onVisibilityChanged(false) at surface: " + this);
              onVisibilityChanged(false);
            }

          } finally {
            mIsCreating = false;
            mSurfaceCreated = true;
            if (redrawNeeded) {
              mSession.finishDrawing(mWindow);
            }
            mIWallpaperEngine.reportShown();
          }
        } catch (RemoteException ex) {
        }
        if (DEBUG)
          Log.v(
              TAG,
              "Layout: x="
                  + mLayout.x
                  + " y="
                  + mLayout.y
                  + " w="
                  + mLayout.width
                  + " h="
                  + mLayout.height);
      }
    }