@Override
  public Bundle getAuthToken(
      AccountAuthenticatorResponse response, Account account, String authTokenType, Bundle options)
      throws NetworkErrorException {
    Log.d(TAG, "getAuthToken(%s)", account.name);

    Bundle result = new Bundle();
    if (AccountData.get(account.name, mContext).isAuthenticated()) {
      Log.d(TAG, "getAuthToken(): Returning dummy SPNEGO auth token");
      result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
      result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);
      result.putString(AccountManager.KEY_AUTHTOKEN, Constants.AUTH_TOKEN);
      result.putInt(HttpNegotiateConstants.KEY_SPNEGO_RESULT, 0);
    } else {
      Log.d(TAG, "getAuthToken(): Asking for credentials confirmation");
      Intent intent =
          SpnegoAuthenticatorActivity.getConfirmCredentialsIntent(mContext, account.name, response);
      result.putParcelable(AccountManager.KEY_INTENT, intent);

      // We need to show a notification in case the caller can't use the intent directly.
      showConfirmCredentialsNotification(mContext, intent);
    }

    return result;
  }
Beispiel #2
0
  /**
   * Restores the encryption key from the given Bundle. Expected to be called when an Activity is
   * being restored after being killed in the background. If the Activity was explicitly killed by
   * the user, Android gives no Bundle (and therefore no key).
   *
   * @param savedInstanceState Bundle containing the Activity's previous state. Null if the user
   *     explicitly killed the Activity.
   * @return True if the data was restored successfully from the Bundle, or if the CipherData in use
   *     matches the Bundle contents.
   */
  public boolean restoreFromBundle(Bundle savedInstanceState) {
    if (savedInstanceState == null) return false;

    byte[] wrappedKey = savedInstanceState.getByteArray(BUNDLE_KEY);
    byte[] iv = savedInstanceState.getByteArray(BUNDLE_IV);
    if (wrappedKey == null || iv == null) return false;

    try {
      Key bundledKey = new SecretKeySpec(wrappedKey, "AES");
      synchronized (mDataLock) {
        if (mData == null) {
          mData = new CipherData(bundledKey, iv);
          return true;
        } else if (mData.key.equals(bundledKey) && Arrays.equals(mData.iv, iv)) {
          return true;
        } else {
          Log.e(TAG, "Attempted to restore different cipher data.");
        }
      }
    } catch (IllegalArgumentException e) {
      Log.e(TAG, "Error in restoring the key from the bundle.");
    }

    return false;
  }
Beispiel #3
0
 private void waitForDebuggerIfNeeded() {
   if (CommandLine.getInstance().hasSwitch(BaseSwitches.WAIT_FOR_JAVA_DEBUGGER)) {
     Log.e(TAG, "Waiting for Java debugger to connect...");
     android.os.Debug.waitForDebugger();
     Log.e(TAG, "Java debugger connected. Resuming execution.");
   }
 }
Beispiel #4
0
  @Override
  protected boolean isStartedUpCorrectly(Intent intent) {
    int tabId = ActivityDelegate.getTabIdFromIntent(getIntent());

    // Fire a MAIN Intent to send the user back through ChromeLauncherActivity.
    Log.e(TAG, "User shouldn't be here.  Sending back to ChromeLauncherActivity.");

    // Try to bring this tab forward after migration.
    Intent tabbedIntent = null;
    if (tabId != Tab.INVALID_TAB_ID) tabbedIntent = Tab.createBringTabToFrontIntent(tabId);

    if (tabbedIntent == null) {
      tabbedIntent = new Intent(Intent.ACTION_MAIN);
      tabbedIntent.setPackage(getPackageName());
    }

    // Launch the other Activity in its own task so it stays when this one finishes.
    tabbedIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    tabbedIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT);

    startActivity(tabbedIntent);
    overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out);

    Log.e(TAG, "Discarding Intent: Tab = " + tabId);
    return false;
  }
 private static void tryObtainingDataDirLockOrDie() {
   StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
   StrictMode.allowThreadDiskWrites();
   try {
     String dataPath = PathUtils.getDataDirectory(ContextUtils.getApplicationContext());
     File lockFile = new File(dataPath, EXCLUSIVE_LOCK_FILE);
     boolean success = false;
     try {
       // Note that the file is not closed intentionally.
       RandomAccessFile file = new RandomAccessFile(lockFile, "rw");
       sExclusiveFileLock = file.getChannel().tryLock();
       success = sExclusiveFileLock != null;
     } catch (IOException e) {
       Log.w(TAG, "Failed to create lock file " + lockFile, e);
     }
     if (!success) {
       Log.w(
           TAG,
           "The app may have another WebView opened in a separate process. "
               + "This is not recommended and may stop working in future versions.");
     }
   } finally {
     StrictMode.setThreadPolicy(oldPolicy);
   }
 }
Beispiel #6
0
  @CalledByNative
  public void startCapture() {
    Log.d(TAG, "startCapture");
    synchronized (mCaptureStateLock) {
      if (mCaptureState != CaptureState.ALLOWED) {
        Log.e(TAG, "startCapture() invoked without user permission.");
        return;
      }
    }
    mMediaProjection = mMediaProjectionManager.getMediaProjection(mResultCode, mResultData);
    if (mMediaProjection == null) {
      Log.e(TAG, "mMediaProjection is null");
      return;
    }
    mMediaProjection.registerCallback(new MediaProjectionCallback(), null);

    mThread = new HandlerThread("ScreenCapture");
    mThread.start();
    mBackgroundHandler = new Handler(mThread.getLooper());

    // On Android M and above, YUV420 is prefered. Some Android L devices will silently
    // fail with YUV420, so keep with RGBA_8888 on L.
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
      mFormat = PixelFormat.RGBA_8888;
    } else {
      mFormat = ImageFormat.YUV_420_888;
    }
    maybeDoRotation();
    createImageReaderWithFormat();
    createVirtualDisplay();

    changeCaptureStateAndNotify(CaptureState.STARTED);
  }
 public ChildProcessConnection allocate(
     Context context,
     ChildProcessConnection.DeathCallback deathCallback,
     ChromiumLinkerParams chromiumLinkerParams,
     boolean alwaysInForeground) {
   synchronized (mConnectionLock) {
     if (mFreeConnectionIndices.isEmpty()) {
       Log.d(TAG, "Ran out of services to allocate.");
       return null;
     }
     int slot = mFreeConnectionIndices.remove(0);
     assert mChildProcessConnections[slot] == null;
     mChildProcessConnections[slot] =
         new ChildProcessConnectionImpl(
             context,
             slot,
             mInSandbox,
             deathCallback,
             mChildClass,
             chromiumLinkerParams,
             alwaysInForeground);
     Log.d(TAG, "Allocator allocated a connection, sandbox: " + mInSandbox + ", slot: " + slot);
     return mChildProcessConnections[slot];
   }
 }
  /**
   * Called from native code to share a surface texture with another child process. Through using
   * the callback object the browser is used as a proxy to route the call to the correct process.
   *
   * @param pid Process handle of the child process to share the SurfaceTexture with.
   * @param surfaceObject The Surface or SurfaceTexture to share with the other child process.
   * @param primaryID Used to route the call to the correct client instance.
   * @param secondaryID Used to route the call to the correct client instance.
   */
  @SuppressWarnings("unused")
  @CalledByNative
  private void establishSurfaceTexturePeer(
      int pid, Object surfaceObject, int primaryID, int secondaryID) {
    if (mCallback == null) {
      Log.e(TAG, "No callback interface has been provided.");
      return;
    }

    Surface surface = null;
    boolean needRelease = false;
    if (surfaceObject instanceof Surface) {
      surface = (Surface) surfaceObject;
    } else if (surfaceObject instanceof SurfaceTexture) {
      surface = new Surface((SurfaceTexture) surfaceObject);
      needRelease = true;
    } else {
      Log.e(TAG, "Not a valid surfaceObject: %s", surfaceObject);
      return;
    }
    try {
      mCallback.establishSurfacePeer(pid, surface, primaryID, secondaryID);
    } catch (RemoteException e) {
      Log.e(TAG, "Unable to call establishSurfaceTexturePeer: %s", e);
      return;
    } finally {
      if (needRelease) {
        surface.release();
      }
    }
  }
    /** Registers this object with the location service. */
    private void registerForLocationUpdates(boolean enableHighAccuracy) {
      ensureLocationManagerCreated();
      if (usePassiveOneShotLocation()) return;

      assert !mIsRunning;
      mIsRunning = true;

      // We're running on the main thread. The C++ side is responsible to
      // bounce notifications to the Geolocation thread as they arrive in the mainLooper.
      try {
        Criteria criteria = new Criteria();
        if (enableHighAccuracy) criteria.setAccuracy(Criteria.ACCURACY_FINE);
        mLocationManager.requestLocationUpdates(
            0, 0, criteria, this, ThreadUtils.getUiThreadLooper());
      } catch (SecurityException e) {
        Log.e(
            TAG,
            "Caught security exception while registering for location updates "
                + "from the system. The application does not have sufficient geolocation "
                + "permissions.");
        unregisterFromLocationUpdates();
        // Propagate an error to JavaScript, this can happen in case of WebView
        // when the embedding app does not have sufficient permissions.
        LocationProviderAdapter.newErrorAvailable(
            "application does not have sufficient " + "geolocation permissions.");
      } catch (IllegalArgumentException e) {
        Log.e(TAG, "Caught IllegalArgumentException registering for location updates.");
        unregisterFromLocationUpdates();
        assert false;
      }
    }
Beispiel #10
0
  /**
   * Return the OpenSSLEngine object corresponding to a given PrivateKey object.
   *
   * <p>This shall only be used for Android 4.1 to work around a platform bug. See
   * https://crbug.com/381465.
   *
   * @param privateKey The PrivateKey handle.
   * @return The OpenSSLEngine object (or null if not available)
   */
  @CalledByNative
  private static Object getOpenSSLEngineForPrivateKey(PrivateKey privateKey) {
    // Find the system OpenSSLEngine class.
    Class<?> engineClass;
    try {
      engineClass = Class.forName("org.apache.harmony.xnet.provider.jsse.OpenSSLEngine");
    } catch (Exception e) {
      // This may happen if the target device has a completely different
      // implementation of the java.security APIs, compared to vanilla
      // Android. Highly unlikely, but still possible.
      Log.e(TAG, "Cannot find system OpenSSLEngine class: " + e);
      return null;
    }

    Object opensslKey = getOpenSSLKeyForPrivateKey(privateKey);
    if (opensslKey == null) return null;

    try {
      // Use reflection to invoke the 'getEngine' method on the
      // result of the getOpenSSLKey().
      Method getEngine;
      try {
        getEngine = opensslKey.getClass().getDeclaredMethod("getEngine");
      } catch (Exception e) {
        // Bail here too, something really not working as expected.
        Log.e(TAG, "No getEngine() method on OpenSSLKey member:" + e);
        return null;
      }
      getEngine.setAccessible(true);
      Object engine = null;
      try {
        engine = getEngine.invoke(opensslKey);
      } finally {
        getEngine.setAccessible(false);
      }
      if (engine == null) {
        // The PrivateKey is probably rotten for some reason.
        Log.e(TAG, "getEngine() returned null");
      }
      // Sanity-check the returned engine.
      if (!engineClass.isInstance(engine)) {
        Log.e(
            TAG,
            "Engine is not an OpenSSLEngine instance, its class name is:"
                + engine.getClass().getCanonicalName());
        return null;
      }
      return engine;

    } catch (Exception e) {
      Log.e(TAG, "Exception while trying to retrieve OpenSSLEngine object: " + e);
      return null;
    }
  }
  private static void startInternal(
      Context context,
      final String[] commandLine,
      int childProcessId,
      FileDescriptorInfo[] filesToBeMapped,
      long clientContext,
      int callbackType,
      boolean inSandbox) {
    try {
      TraceEvent.begin("ChildProcessLauncher.startInternal");

      ChildProcessConnection allocatedConnection = null;
      synchronized (ChildProcessLauncher.class) {
        if (inSandbox) {
          allocatedConnection = sSpareSandboxedConnection;
          sSpareSandboxedConnection = null;
        }
      }
      if (allocatedConnection == null) {
        boolean alwaysInForeground = false;
        if (callbackType == CALLBACK_FOR_GPU_PROCESS) alwaysInForeground = true;
        allocatedConnection =
            allocateBoundConnection(context, commandLine, inSandbox, alwaysInForeground);
        if (allocatedConnection == null) {
          Log.d(TAG, "Allocation of new service failed. Queuing up pending spawn.");
          sPendingSpawnQueue.enqueue(
              new PendingSpawnData(
                  context,
                  commandLine,
                  childProcessId,
                  filesToBeMapped,
                  clientContext,
                  callbackType,
                  inSandbox));
          return;
        }
      }

      Log.d(
          TAG, "Setting up connection to process: slot=" + allocatedConnection.getServiceNumber());
      triggerConnectionSetup(
          allocatedConnection,
          commandLine,
          childProcessId,
          filesToBeMapped,
          callbackType,
          clientContext);
    } finally {
      TraceEvent.end("ChildProcessLauncher.startInternal");
    }
  }
  @SuppressWarnings("unused")
  @CalledByNative
  private void destroySurfaceTextureSurface(int surfaceTextureId, int clientId) {
    if (mCallback == null) {
      Log.e(TAG, "No callback interface has been provided.");
      return;
    }

    try {
      mCallback.unregisterSurfaceTextureSurface(surfaceTextureId, clientId);
    } catch (RemoteException e) {
      Log.e(TAG, "Unable to call unregisterSurfaceTextureSurface: %s", e);
    }
  }
  @SuppressWarnings("unused")
  @CalledByNative
  private Surface getSurfaceTextureSurface(int surfaceTextureId) {
    if (mCallback == null) {
      Log.e(TAG, "No callback interface has been provided.");
      return null;
    }

    try {
      return mCallback.getSurfaceTextureSurface(surfaceTextureId).getSurface();
    } catch (RemoteException e) {
      Log.e(TAG, "Unable to call getSurfaceTextureSurface: %s", e);
      return null;
    }
  }
Beispiel #14
0
 // This method was deprecated in API level 23 by onAttach(Context).
 // TODO(braveyao): remove this method after the minSdkVersion of chrome is 23,
 // https://crbug.com/614172.
 @SuppressWarnings("deprecation")
 @Override
 public void onAttach(Activity activity) {
   super.onAttach(activity);
   Log.d(TAG, "onAttach");
   changeCaptureStateAndNotify(CaptureState.ATTACHED);
 }
  /** @see BaseInputConnection#setComposingRegion(int, int) */
  @Override
  public boolean setComposingRegion(int start, int end) {
    if (DEBUG) Log.w(TAG, "setComposingRegion [" + start + " " + end + "]");
    int textLength = mEditable.length();
    int a = Math.min(start, end);
    int b = Math.max(start, end);
    if (a < 0) a = 0;
    if (b < 0) b = 0;
    if (a > textLength) a = textLength;
    if (b > textLength) b = textLength;

    CharSequence regionText = null;
    if (a == b) {
      removeComposingSpans(mEditable);
    } else {
      if (a == 0 && b == mEditable.length()) {
        regionText = mEditable.subSequence(a, b);
        // If setting composing region that matches, at least in length, of the entire
        // editable region then check it for image placeholders.  If any are found,
        // don't continue this operation.
        // This fixes the problem where, on Android 4.3, pasting an image is followed
        // by setting the composing region which then causes the image to be deleted.
        // http://crbug.com/466755
        for (int i = a; i < b; ++i) {
          if (regionText.charAt(i) == '\uFFFC') return true;
        }
      }
      super.setComposingRegion(a, b);
    }
    updateSelectionIfRequired();

    return mImeAdapter.setComposingRegion(regionText, a, b);
  }
  @Override
  protected void onCreate(final Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    String[] parameters = getIntent().getStringArrayExtra(EXTRAS);
    if (parameters != null) {
      for (String s : parameters) {
        s = s.replace("\\,", ",");
      }
    }
    if (Intent.ACTION_VIEW.equals(getIntent().getAction())) {
      Uri uri = getIntent().getData();
      if (uri != null) {
        Log.i(TAG, "MojoShellActivity opening " + uri);
        if (parameters == null) {
          parameters = new String[] {uri.toString()};
        } else {
          String[] newParameters = new String[parameters.length + 1];
          System.arraycopy(parameters, 0, newParameters, 0, parameters.length);
          newParameters[parameters.length] = uri.toString();
          parameters = newParameters;
        }
      }
    }

    // TODO(ppi): Gotcha - the call below will work only once per process lifetime, but the OS
    // has no obligation to kill the application process between destroying and restarting the
    // activity. If the application process is kept alive, initialization parameters sent with
    // the intent will be stale.
    // TODO(qsr): We should be passing application context here as required by
    // InitApplicationContext on the native side. Currently we can't, as PlatformViewportAndroid
    // relies on this being the activity context.
    ShellMain.ensureInitialized(this, parameters);
    ShellMain.start();
  }
 @Override
 @SuppressFBWarnings("DM_EXIT")
 public void onDestroy() {
   Log.i(TAG, "Destroying ChildProcessService pid=%d", Process.myPid());
   super.onDestroy();
   if (mActivitySemaphore.tryAcquire()) {
     // TODO(crbug.com/457406): This is a bit hacky, but there is no known better solution
     // as this service will get reused (at least if not sandboxed).
     // In fact, we might really want to always exit() from onDestroy(), not just from
     // the early return here.
     System.exit(0);
     return;
   }
   synchronized (mMainThread) {
     try {
       while (!mLibraryInitialized) {
         // Avoid a potential race in calling through to native code before the library
         // has loaded.
         mMainThread.wait();
       }
     } catch (InterruptedException e) {
       // Ignore
     }
   }
   // Try to shutdown the MainThread gracefully, but it might not
   // have chance to exit normally.
   nativeShutdownMainThread();
 }
 private void ensureLocationManagerCreated() {
   if (mLocationManager != null) return;
   mLocationManager = (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
   if (mLocationManager == null) {
     Log.e(TAG, "Could not get location manager.");
   }
 }
Beispiel #19
0
  // SET_VOLUME messages have a |level| and |muted| properties. One of them is
  // |null| and the other one isn't. |muted| is expected to be a boolean while
  // |level| is a float from 0.0 to 1.0.
  // Example:
  // {
  //   "volume" {
  //     "level": 0.9,
  //     "muted": null
  //   }
  // }
  @Override
  public HandleVolumeMessageResult handleVolumeMessage(
      JSONObject volume, final String clientId, final int sequenceNumber) throws JSONException {
    if (volume == null) return new HandleVolumeMessageResult(false, false);

    if (isApiClientInvalid()) return new HandleVolumeMessageResult(false, false);

    boolean waitForVolumeChange = false;
    try {
      if (!volume.isNull("muted")) {
        boolean newMuted = volume.getBoolean("muted");
        if (Cast.CastApi.isMute(mApiClient) != newMuted) {
          Cast.CastApi.setMute(mApiClient, newMuted);
          waitForVolumeChange = true;
        }
      }
      if (!volume.isNull("level")) {
        double newLevel = volume.getDouble("level");
        double currentLevel = Cast.CastApi.getVolume(mApiClient);
        if (!Double.isNaN(currentLevel)
            && Math.abs(currentLevel - newLevel) > MIN_VOLUME_LEVEL_DELTA) {
          Cast.CastApi.setVolume(mApiClient, newLevel);
          waitForVolumeChange = true;
        }
      }
    } catch (IOException e) {
      Log.e(TAG, "Failed to send volume command: " + e);
      return new HandleVolumeMessageResult(false, false);
    }

    return new HandleVolumeMessageResult(true, waitForVolumeChange);
  }
 @Override
 public Bundle confirmCredentials(
     AccountAuthenticatorResponse response, Account account, Bundle options)
     throws NetworkErrorException {
   Log.d(TAG, "confirmCredentials(%s)", account.name);
   return unsupportedOperationBundle("confirmCredentials");
 }
 @Override
 public Bundle updateCredentials(
     AccountAuthenticatorResponse response, Account account, String authTokenType, Bundle options)
     throws NetworkErrorException {
   Log.d(TAG, "updateCredentials(%s)", account.name);
   return unsupportedOperationBundle("updateCredentials");
 }
 @CalledByNative
 private void focusedNodeChanged(boolean isEditable) {
   Log.d(TAG, "focusedNodeChanged: isEditable [%b]", isEditable);
   if (mTextInputType != TextInputType.NONE && mInputConnection != null && isEditable) {
     restartInput();
   }
 }
 /** Move cursor to the end of the current selection. */
 public void moveCursorToSelectionEnd() {
   Log.d(TAG, "movecursorToEnd");
   if (mInputConnection != null) {
     int selectionEnd = Selection.getSelectionEnd(mEditable);
     mInputConnection.setSelection(selectionEnd, selectionEnd);
   }
 }
 /** @see BaseInputConnection#endBatchEdit() */
 @Override
 public boolean endBatchEdit() {
   if (mNumNestedBatchEdits == 0) return false;
   --mNumNestedBatchEdits;
   if (DEBUG) Log.w(TAG, "endBatchEdit [" + (mNumNestedBatchEdits == 0) + "]");
   if (mNumNestedBatchEdits == 0) updateSelectionIfRequired();
   return mNumNestedBatchEdits != 0;
 }
  @SuppressWarnings("unused")
  @CalledByNative
  private void createSurfaceTextureSurface(
      int surfaceTextureId, int clientId, SurfaceTexture surfaceTexture) {
    if (mCallback == null) {
      Log.e(TAG, "No callback interface has been provided.");
      return;
    }

    Surface surface = new Surface(surfaceTexture);
    try {
      mCallback.registerSurfaceTextureSurface(surfaceTextureId, clientId, surface);
    } catch (RemoteException e) {
      Log.e(TAG, "Unable to call registerSurfaceTextureSurface: %s", e);
    }
    surface.release();
  }
 public boolean dispatchKeyEvent(KeyEvent event) {
   Log.d(
       TAG, "dispatchKeyEvent: action [%d], keycode [%d]", event.getAction(), event.getKeyCode());
   if (mInputConnection != null) {
     return mInputConnection.sendKeyEvent(event);
   }
   return sendKeyEvent(event);
 }
Beispiel #27
0
  @CalledByNative
  public void stopCapture() {
    Log.d(TAG, "stopCapture");
    synchronized (mCaptureStateLock) {
      if (mMediaProjection != null && mCaptureState == CaptureState.STARTED) {
        mMediaProjection.stop();
        changeCaptureStateAndNotify(CaptureState.STOPPING);
      }

      while (mCaptureState != CaptureState.STOPPED) {
        try {
          mCaptureStateLock.wait();
        } catch (InterruptedException ex) {
          Log.e(TAG, "ScreenCaptureEvent: " + ex);
        }
      }
    }
  }
Beispiel #28
0
 /**
  * Always process the violation on the UI thread. This ensures other crash reports are not
  * corrupted. Since each individual user has a very small chance of uploading each violation, and
  * we have a hard cap of 3 per session, this will not affect performance too much.
  *
  * @param violationInfo The violation info from the StrictMode violation in question.
  */
 @UiThread
 private static void reportStrictModeViolation(Object violationInfo) {
   try {
     Field crashInfoField = violationInfo.getClass().getField("crashInfo");
     ApplicationErrorReport.CrashInfo crashInfo =
         (ApplicationErrorReport.CrashInfo) crashInfoField.get(violationInfo);
     String stackTrace = crashInfo.stackTrace;
     if (stackTrace == null) {
       Log.d(TAG, "StrictMode violation stack trace was null.");
     } else {
       Log.d(TAG, "Upload stack trace: " + stackTrace);
       JavaExceptionReporter.reportStackTrace(stackTrace);
     }
   } catch (Exception e) {
     // Ignore all exceptions.
     Log.d(TAG, "Could not handle observed StrictMode violation.", e);
   }
 }
 private static void deleteFileForOverwrite(DownloadInfo info) {
   assert !ThreadUtils.runningOnUiThread();
   File dir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
   if (!dir.isDirectory()) return;
   final File file = new File(dir, info.getFileName());
   if (!file.delete()) {
     Log.e(TAG, "Failed to delete a file: " + info.getFileName());
   }
 }
 /** Show soft keyboard only if it is the current keyboard configuration. */
 private void showSoftKeyboard() {
   Log.d(TAG, "showSoftKeyboard");
   mInputMethodManagerWrapper.showSoftInput(
       mViewEmbedder.getAttachedView(), 0, mViewEmbedder.getNewShowKeyboardReceiver());
   if (mViewEmbedder.getAttachedView().getResources().getConfiguration().keyboard
       != Configuration.KEYBOARD_NOKEYS) {
     mViewEmbedder.onKeyboardBoundsUnchanged();
   }
 }