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); }
/** * 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> * <manifest ...> * * ... * * <application ...> * <meta-data * android:name="com.parse.APPLICATION_ID" * android:value="@string/parse_app_id" /> * <meta-data * android:name="com.parse.CLIENT_KEY" * android:value="@string/parse_client_key" /> * * ... * * </application> * </manifest> * </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); }
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; }
/** * 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; }
/** * 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, "your application id", "your client key"); * } * } * </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; } }