private void performPlaceHolderSubstitution(
      ManifestInfo manifestInfo,
      XmlDocument xmlDocument,
      MergingReport.Builder mergingReportBuilder) {

    // check for placeholders presence, switch first the packageName and application id if
    // it is not explicitly set.
    Map<String, Object> finalPlaceHolderValues = mPlaceHolderValues;
    if (!mPlaceHolderValues.containsKey("applicationId")) {
      String packageName =
          manifestInfo.getMainManifestPackageName().isPresent()
              ? manifestInfo.getMainManifestPackageName().get()
              : xmlDocument.getPackageName();
      // add all existing placeholders except package name that will be swapped.
      ImmutableMap.Builder<String, Object> builder = ImmutableMap.<String, Object>builder();
      for (Map.Entry<String, Object> entry : mPlaceHolderValues.entrySet()) {
        if (!entry.getKey().equals(PlaceholderHandler.PACKAGE_NAME)) {
          builder.put(entry);
        }
      }
      finalPlaceHolderValues =
          builder
              .put(PlaceholderHandler.PACKAGE_NAME, packageName)
              .put(PlaceholderHandler.APPLICATION_ID, packageName)
              .build();
    }

    KeyBasedValueResolver<String> placeHolderValueResolver =
        new MapBasedKeyBasedValueResolver<String>(finalPlaceHolderValues);
    PlaceholderHandler placeholderHandler = new PlaceholderHandler();
    placeholderHandler.visit(
        mMergeType, xmlDocument, placeHolderValueResolver, mergingReportBuilder);
  }
  /**
   * Load an xml file and perform placeholder substitution
   *
   * @param manifestInfo the android manifest information like if it is a library, an overlay or a
   *     main manifest file.
   * @param selectors all the libraries selectors
   * @param mergingReportBuilder the merging report to store events and errors.
   * @return a loaded manifest info.
   * @throws MergeFailureException
   */
  private LoadedManifestInfo load(
      ManifestInfo manifestInfo,
      KeyResolver<String> selectors,
      MergingReport.Builder mergingReportBuilder)
      throws MergeFailureException {

    XmlDocument xmlDocument;
    try {
      xmlDocument =
          XmlLoader.load(
              selectors,
              mSystemPropertyResolver,
              manifestInfo.mName,
              manifestInfo.mLocation,
              manifestInfo.getType(),
              manifestInfo.getMainManifestPackageName());
    } catch (Exception e) {
      throw new MergeFailureException(e);
    }

    String originalPackageName = xmlDocument.getPackageName();
    MergingReport.Builder builder =
        manifestInfo.getType() == XmlDocument.Type.MAIN
            ? mergingReportBuilder
            : new MergingReport.Builder(mergingReportBuilder.getLogger());

    builder.getActionRecorder().recordDefaultNodeAction(xmlDocument.getRootNode());

    // perform place holder substitution, this is necessary to do so early in case placeholders
    // are used in key attributes.
    performPlaceHolderSubstitution(manifestInfo, xmlDocument, builder);

    return new LoadedManifestInfo(
        manifestInfo, Optional.fromNullable(originalPackageName), xmlDocument);
  }
예제 #3
0
  /**
   * Authenticates this client as belonging to your application.
   *
   * <p>You must define {@code com.parse.APPLICATION_ID} and {@code com.parse.CLIENT_KEY} {@code
   * meta-data} in your {@code AndroidManifest.xml}:
   *
   * <pre>
   * &lt;manifest ...&gt;
   *
   * ...
   *
   *   &lt;application ...&gt;
   *     &lt;meta-data
   *       android:name="com.parse.APPLICATION_ID"
   *       android:value="@string/parse_app_id" /&gt;
   *     &lt;meta-data
   *       android:name="com.parse.CLIENT_KEY"
   *       android:value="@string/parse_client_key" /&gt;
   *
   *       ...
   *
   *   &lt;/application&gt;
   * &lt;/manifest&gt;
   * </pre>
   *
   * <p>This must be called before your application can use the Parse library. The recommended way
   * is to put a call to {@code Parse.initialize} in your {@code Application}'s {@code onCreate}
   * method:
   *
   * <p>
   *
   * <pre>
   * public class MyApplication extends Application {
   *   public void onCreate() {
   *     Parse.initialize(this);
   *   }
   * }
   * </pre>
   *
   * @param context The active {@link Context} for your application.
   */
  public static void initialize(Context context) {
    Context applicationContext = context.getApplicationContext();
    String applicationId;
    String clientKey;
    Bundle metaData = ManifestInfo.getApplicationMetadata(applicationContext);
    if (metaData != null) {
      applicationId = metaData.getString(PARSE_APPLICATION_ID);
      clientKey = metaData.getString(PARSE_CLIENT_KEY);

      if (applicationId == null) {
        throw new RuntimeException(
            "ApplicationId not defined. "
                + "You must provide ApplicationId in AndroidManifest.xml.\n"
                + "<meta-data\n"
                + "    android:name=\"com.parse.APPLICATION_ID\"\n"
                + "    android:value=\"<Your Application Id>\" />");
      }
      if (clientKey == null) {
        throw new RuntimeException(
            "ClientKey not defined. "
                + "You must provide ClientKey in AndroidManifest.xml.\n"
                + "<meta-data\n"
                + "    android:name=\"com.parse.CLIENT_KEY\"\n"
                + "    android:value=\"<Your Client Key>\" />");
      }
    } else {
      throw new RuntimeException("Can't get Application Metadata");
    }
    initialize(context, applicationId, clientKey);
  }
예제 #4
0
 private static boolean allParsePushIntentReceiversInternal()
 {
   Iterator localIterator = ManifestInfo.getIntentReceivers(new String[] { "com.parse.push.intent.RECEIVE", "com.parse.push.intent.DELETE", "com.parse.push.intent.OPEN" }).iterator();
   while (localIterator.hasNext()) {
     if (nextactivityInfo.exported) {
       return false;
     }
   }
   return true;
 }
 private LoadedManifestInfo(
     @NonNull ManifestInfo manifestInfo,
     @NonNull Optional<String> originalPackageName,
     @NonNull XmlDocument xmlDocument) {
   super(
       manifestInfo.mName,
       manifestInfo.mLocation,
       manifestInfo.mType,
       manifestInfo.getMainManifestPackageName());
   mXmlDocument = xmlDocument;
   mOriginalPackageName = originalPackageName;
 }
예제 #6
0
  /**
   * Checks that each of the receivers associated with the three actions defined in
   * ParsePushBroadcastReceiver (ACTION_PUSH_RECEIVE, ACTION_PUSH_OPEN, ACTION_PUSH_DELETE) has
   * their exported attributes set to false. If this is the case for each of the receivers
   * registered in the AndroidManifest.xml or if no receivers are registered (because we will be
   * registering the default implementation of ParsePushBroadcastReceiver in PushService) then true
   * is returned. Note: the reason for iterating through lists, is because you can define different
   * receivers in the manifest that respond to the same intents and both all of the receivers will
   * be triggered. So we want to make sure all them have the exported attribute set to false.
   */
  private static boolean allParsePushIntentReceiversInternal() {
    List<ResolveInfo> intentReceivers =
        ManifestInfo.getIntentReceivers(
            ParsePushBroadcastReceiver.ACTION_PUSH_RECEIVE,
            ParsePushBroadcastReceiver.ACTION_PUSH_DELETE,
            ParsePushBroadcastReceiver.ACTION_PUSH_OPEN);

    for (ResolveInfo resolveInfo : intentReceivers) {
      if (resolveInfo.activityInfo.exported) {
        return false;
      }
    }
    return true;
  }
예제 #7
0
  /**
   * Authenticates this client as belonging to your application.
   *
   * <p>This method is only required if you intend to use a different {@code applicationId} or
   * {@code clientKey} than is defined by {@code com.parse.APPLICATION_ID} or {@code
   * com.parse.CLIENT_KEY} in your {@code AndroidManifest.xml}.
   *
   * <p>This must be called before your application can use the Parse library. The recommended way
   * is to put a call to {@code Parse.initialize} in your {@code Application}'s {@code onCreate}
   * method:
   *
   * <p>
   *
   * <pre>
   * public class MyApplication extends Application {
   *   public void onCreate() {
   *     Parse.initialize(this, &quot;your application id&quot;, &quot;your client key&quot;);
   *   }
   * }
   * </pre>
   *
   * @param context The active {@link Context} for your application.
   * @param applicationId The application id provided in the Parse dashboard.
   * @param clientKey The client key provided in the Parse dashboard.
   */
  public static void initialize(Context context, String applicationId, String clientKey) {
    ParsePlugins.Android.initialize(context, applicationId, clientKey);
    Context applicationContext = context.getApplicationContext();

    ParseHttpClient.setKeepAlive(true);
    ParseHttpClient.setMaxConnections(20);
    ParseRequest.setDefaultClient(ParsePlugins.get().restClient());
    // If we have interceptors in list, we have to initialize all http clients and add interceptors
    if (interceptors != null) {
      initializeParseHttpClientsWithParseNetworkInterceptors();
    }

    ParseObject.registerParseSubclasses();

    if (isLocalDatastoreEnabled()) {
      offlineStore = new OfflineStore(context);
    } else {
      ParseKeyValueCache.initialize(context);
    }

    // Make sure the data on disk for Parse is for the current
    // application.
    checkCacheApplicationId();
    new Thread("Parse.initialize Disk Check & Starting Command Cache") {
      @Override
      public void run() {
        // Trigger the command cache to flush its contents.
        getEventuallyQueue();
      }
    }.start();

    ParseFieldOperations.registerDefaultDecoders();

    if (!allParsePushIntentReceiversInternal()) {
      throw new SecurityException(
          "To prevent external tampering to your app's notifications, "
              + "all receivers registered to handle the following actions must have "
              + "their exported attributes set to false: com.parse.push.intent.RECEIVE, "
              + "com.parse.push.intent.OPEN, com.parse.push.intent.DELETE");
    }

    // May need to update GCM registration ID if app version has changed.
    // This also primes current installation.
    GcmRegistrar.getInstance()
        .registerAsync()
        .continueWithTask(
            new Continuation<Void, Task<Void>>() {
              @Override
              public Task<Void> then(Task<Void> task) throws Exception {
                // Prime current user in the background
                return ParseUser.getCurrentUserAsync().makeVoid();
              }
            })
        .continueWith(
            new Continuation<Void, Void>() {
              @Override
              public Void then(Task<Void> task) throws Exception {
                // Prime config in the background
                ParseConfig.getCurrentConfig();
                return null;
              }
            },
            Task.BACKGROUND_EXECUTOR);

    if (ManifestInfo.getPushType() == PushType.PPNS) {
      PushService.startServiceIfRequired(applicationContext);
    }

    dispatchOnParseInitialized();

    // FYI we probably don't want to do this if we ever add other callbacks.
    synchronized (MUTEX_CALLBACKS) {
      Parse.callbacks = null;
    }
  }