Android Open Source - android-sdk Mraid Display Controller






From Project

Back to project page android-sdk.

License

The source code is released under:

Copyright (c) 2013 Adcash OU. All rights reserved under Creative Commons Attribution 3.0 Unported http://creativecommons.org/licenses/by/3.0/ Redistribution and use in source and binary forms, with or...

If you think the Android project android-sdk listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

/*
 * Copyright (c) 2010-2013, Adcash OU.//from   www  . jav a  2 s  .c  o m
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *  Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 *
 *  Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in the
 *   documentation and/or other materials provided with the distribution.
 *
 *  Neither the name of 'MoPub Inc.' nor the names of its contributors
 *   may be used to endorse or promote products derived from this software
 *   without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package com.adcash.mobileads;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.graphics.Color;
import android.graphics.Rect;
import android.graphics.drawable.StateListDrawable;
import android.media.MediaScannerConnection;
import android.net.Uri;
import android.os.Environment;
import android.os.Handler;
import android.provider.CalendarContract;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.webkit.URLUtil;
import android.widget.FrameLayout;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.Toast;
import com.adcash.mobileads.MraidView.ExpansionStyle;
import com.adcash.mobileads.MraidView.NativeCloseButtonStyle;
import com.adcash.mobileads.MraidView.PlacementType;
import com.adcash.mobileads.MraidView.ViewState;
import com.adcash.mobileads.factories.HttpClientFactory;
import com.adcash.mobileads.util.HttpResponses;
import com.adcash.mobileads.util.Mraids;
import com.adcash.mobileads.util.Streams;
import org.apache.http.Header;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;

import java.io.*;
import java.net.URI;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

import static com.adcash.mobileads.MraidCommandFactory.MraidJavascriptCommand.CREATE_CALENDAR_EVENT;
import static com.adcash.mobileads.MraidCommandFactory.MraidJavascriptCommand.EXPAND;
import static com.adcash.mobileads.MraidCommandFactory.MraidJavascriptCommand.GET_CURRENT_POSITION;
import static com.adcash.mobileads.MraidCommandFactory.MraidJavascriptCommand.GET_DEFAULT_POSITION;
import static com.adcash.mobileads.MraidCommandFactory.MraidJavascriptCommand.GET_MAX_SIZE;
import static com.adcash.mobileads.MraidCommandFactory.MraidJavascriptCommand.GET_SCREEN_SIZE;
import static com.adcash.mobileads.MraidCommandFactory.MraidJavascriptCommand.STORE_PICTURE;
import static com.adcash.mobileads.MraidCommandStorePicture.MIME_TYPE_HEADER;
import static com.adcash.mobileads.MraidView.BaseMraidListener;
import static com.adcash.mobileads.resource.Drawables.INTERSTITIAL_CLOSE_BUTTON_NORMAL;
import static com.adcash.mobileads.resource.Drawables.INTERSTITIAL_CLOSE_BUTTON_PRESSED;
import static com.adcash.mobileads.util.Mraids.ANDROID_CALENDAR_CONTENT_TYPE;
import static com.adcash.mobileads.util.Mraids.isCalendarAvailable;
import static com.adcash.mobileads.util.Mraids.isInlineVideoAvailable;
import static com.adcash.mobileads.util.Mraids.isSmsAvailable;
import static com.adcash.mobileads.util.Mraids.isStorePictureSupported;
import static com.adcash.mobileads.util.Mraids.isTelAvailable;
import static com.adcash.mobileads.util.ResponseHeader.LOCATION;

class MraidDisplayController extends MraidAbstractController {
    private static final String LOGTAG = "MraidDisplayController";
    private static final long VIEWABILITY_TIMER_MILLIS = 3000;
    private static final int CLOSE_BUTTON_SIZE_DP = 50;
    private static final String[] DATE_FORMATS = {
            "yyyy-MM-dd'T'HH:mm:ssZZZZZ",
            "yyyy-MM-dd'T'HH:mmZZZZZ"
    };
    private static final int MAX_NUMBER_DAYS_IN_MONTH = 31;

    // The view's current state.
    private ViewState mViewState = ViewState.HIDDEN;

    // Tracks whether this controller's view responds to expand() calls.
    private final ExpansionStyle mExpansionStyle;

    // Tracks how this controller's view should display its native close button.
    private final NativeCloseButtonStyle mNativeCloseButtonStyle;

    // Separate instance of MraidView, for displaying "two-part" creatives via the expand(URL) API.
    private MraidView mTwoPartExpansionView;

    // A reference to the root view.
    private FrameLayout mRootView;

    // Tracks whether this controller's view is currently on-screen.
    private boolean mIsViewable;

    // Task that periodically checks whether this controller's view is on-screen.
    private Runnable mCheckViewabilityTask = new Runnable() {
        public void run() {
            boolean currentViewable = checkViewable();
            if (mIsViewable != currentViewable) {
                mIsViewable = currentViewable;
                getMraidView().fireChangeEventForProperty(
                        MraidViewableProperty.createWithViewable(mIsViewable));
            }
            mHandler.postDelayed(this, VIEWABILITY_TIMER_MILLIS);
        }
    };

    // Handler for scheduling viewability checks.
    private Handler mHandler = new Handler();

    // Stores the requested orientation for the Activity to which this controller's view belongs.
    // This is needed to restore the Activity's requested orientation in the event that the view
    // itself requires an orientation lock.
    private final int mOriginalRequestedOrientation;

    private OrientationBroadcastReceiver mOrientationBroadcastReceiver = new OrientationBroadcastReceiver();

    // Native close button, used for expanded content.
    private ImageView mCloseButton;

    // Tracks whether expanded content provides its own, non-native close button.
    private boolean mAdWantsCustomCloseButton;

    // The scale factor for a dip (relative to a 160 dpi screen).
    protected float mDensity;

    // The width of the screen in pixels.
    protected int mScreenWidth = -1;

    // The height of the screen in pixels.
    protected int mScreenHeight = -1;

    // The view's position within its parent.
    private int mViewIndexInParent;

    // A view that replaces the MraidView within its parent view when the MraidView is expanded
    // (i.e. moved to the top of the view hierarchy).
    private FrameLayout mPlaceholderView;
    private FrameLayout mAdContainerLayout;
    private RelativeLayout mExpansionLayout;

    MraidDisplayController(MraidView view, MraidView.ExpansionStyle expStyle,
            MraidView.NativeCloseButtonStyle buttonStyle) {
        super(view);
        mExpansionStyle = expStyle;
        mNativeCloseButtonStyle = buttonStyle;

        Context context = getContext();
        mOriginalRequestedOrientation = (context instanceof Activity) ?
                ((Activity) context).getRequestedOrientation() :
                ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;

        mAdContainerLayout = createAdContainerLayout();
        mExpansionLayout = createExpansionLayout();
        mPlaceholderView = createPlaceholderView();

        initialize();
    }

    private void initialize() {
        mViewState = ViewState.LOADING;
        initializeScreenMetrics();
        initializeViewabilityTimer();
        mOrientationBroadcastReceiver.register(getContext());
    }

    private void initializeScreenMetrics() {
        Context context = getContext();
        DisplayMetrics metrics = new DisplayMetrics();
        WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        wm.getDefaultDisplay().getMetrics(metrics);
        mDensity = metrics.density;

        int statusBarHeight = 0, titleBarHeight = 0;
        if (context instanceof Activity) {
            Activity activity = (Activity) context;
            Window window = activity.getWindow();
            Rect rect = new Rect();
            window.getDecorView().getWindowVisibleDisplayFrame(rect);
            statusBarHeight = rect.top;
            int contentViewTop = window.findViewById(Window.ID_ANDROID_CONTENT).getTop();
            titleBarHeight = contentViewTop - statusBarHeight;
        }

        int widthPixels = metrics.widthPixels;
        int heightPixels = metrics.heightPixels - statusBarHeight - titleBarHeight;
        mScreenWidth = (int) (widthPixels * (160.0 / metrics.densityDpi));
        mScreenHeight = (int) (heightPixels * (160.0 / metrics.densityDpi));
    }

    private void initializeViewabilityTimer() {
        mHandler.removeCallbacks(mCheckViewabilityTask);
        mHandler.post(mCheckViewabilityTask);
    }

    private int getDisplayRotation() {
        WindowManager wm = (WindowManager) getContext()
                .getSystemService(Context.WINDOW_SERVICE);
        return wm.getDefaultDisplay().getOrientation();
    }

    private void onOrientationChanged(int currentRotation) {
        initializeScreenMetrics();
        getMraidView().fireChangeEventForProperty(
                MraidScreenSizeProperty.createWithSize(mScreenWidth, mScreenHeight));
    }

    public void destroy() {
        mHandler.removeCallbacks(mCheckViewabilityTask);
        try {
            mOrientationBroadcastReceiver.unregister();
        } catch (IllegalArgumentException e) {
            if (!e.getMessage().contains("Receiver not registered")) {
                throw e;
            } // Else ignore this exception.
        }
    }

    protected void initializeJavaScriptState() {
        ArrayList<MraidProperty> properties = new ArrayList<MraidProperty>();
        properties.add(MraidScreenSizeProperty.createWithSize(mScreenWidth, mScreenHeight));
        properties.add(MraidViewableProperty.createWithViewable(mIsViewable));
        getMraidView().fireChangeEventForProperties(properties);

        mViewState = ViewState.DEFAULT;
        getMraidView().fireChangeEventForProperty(MraidStateProperty.createWithViewState(mViewState));
        initializeSupportedFunctionsProperty();
    }

    protected boolean isExpanded() {
        return (mViewState == ViewState.EXPANDED);
    }

    protected void close() {
        if (mViewState == ViewState.EXPANDED) {
            resetViewToDefaultState();
            setOrientationLockEnabled(false);
            mViewState = ViewState.DEFAULT;
            getMraidView().fireChangeEventForProperty(MraidStateProperty.createWithViewState(mViewState));
        } else if (mViewState == ViewState.DEFAULT) {
            getMraidView().setVisibility(View.INVISIBLE);
            mViewState = ViewState.HIDDEN;
            getMraidView().fireChangeEventForProperty(MraidStateProperty.createWithViewState(mViewState));
        }

        if (getMraidView().getMraidListener() != null) {
            getMraidView().getMraidListener().onClose(getMraidView(), mViewState);
        }
    }

    private void resetViewToDefaultState() {
        setNativeCloseButtonEnabled(false);
        mAdContainerLayout.removeAllViewsInLayout();
        mExpansionLayout.removeAllViewsInLayout();
        mRootView.removeView(mExpansionLayout);

        getMraidView().requestLayout();

        ViewGroup parent = (ViewGroup) mPlaceholderView.getParent();
        parent.addView(getMraidView(), mViewIndexInParent);
        parent.removeView(mPlaceholderView);
        parent.invalidate();
    }

    protected void expand(String url, int width, int height, boolean shouldUseCustomClose,
            boolean shouldLockOrientation) {
        if (mExpansionStyle == MraidView.ExpansionStyle.DISABLED) return;

        if (url != null && !URLUtil.isValidUrl(url)) {
            getMraidView().fireErrorEvent(EXPAND, "URL passed to expand() was invalid.");
            return;
        }

        // Obtain the root content view, since that's where we're going to insert the expanded 
        // content. We must do this before swapping the MraidView with its place-holder;
        // otherwise, getRootView() will return the wrong view (or null).
        mRootView = (FrameLayout) getMraidView().getRootView().findViewById(android.R.id.content);

        useCustomClose(shouldUseCustomClose);
        setOrientationLockEnabled(shouldLockOrientation);
        swapViewWithPlaceholderView();

        View expansionContentView = getMraidView();
        if (url != null) {
            mTwoPartExpansionView = new MraidView(getContext(), getMraidView().getAdConfiguration(), ExpansionStyle.DISABLED,
                    NativeCloseButtonStyle.AD_CONTROLLED, PlacementType.INLINE);
            mTwoPartExpansionView.setMraidListener(new BaseMraidListener() {
                public void onClose(MraidView view, ViewState newViewState) {
                    close();
                }
            });
            mTwoPartExpansionView.loadUrl(url);
            expansionContentView = mTwoPartExpansionView;
        }

        expandLayouts(expansionContentView, (int) (width * mDensity), (int) (height * mDensity));
        mRootView.addView(mExpansionLayout, new RelativeLayout.LayoutParams(
                RelativeLayout.LayoutParams.FILL_PARENT, RelativeLayout.LayoutParams.FILL_PARENT));

        if (mNativeCloseButtonStyle == MraidView.NativeCloseButtonStyle.ALWAYS_VISIBLE ||
                (!mAdWantsCustomCloseButton &&
                mNativeCloseButtonStyle != MraidView.NativeCloseButtonStyle.ALWAYS_HIDDEN)) {
            setNativeCloseButtonEnabled(true);
        }

        mViewState = ViewState.EXPANDED;
        getMraidView().fireChangeEventForProperty(MraidStateProperty.createWithViewState(mViewState));
        if (getMraidView().getMraidListener() != null) getMraidView().getMraidListener().onExpand(getMraidView());
    }

    protected void showUserDownloadImageAlert(String imageUrl) {
        Context context = getContext();
        if (!isStorePictureSupported(context)) {
            getMraidView().fireErrorEvent(STORE_PICTURE, "Error downloading file - the device does not have an SD card mounted, or the Android permission is not granted.");
            Log.d("Adcash", "Error downloading file - the device does not have an SD card mounted, or the Android permission is not granted.");
            return;
        }

        if (context instanceof Activity) {
            showUserDialog(imageUrl);
        } else {
            showUserToast("Downloading image to Picture gallery...");
            downloadImage(imageUrl);
        }
    }

    private void showUserToast(final String message) {
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(getContext(), message, Toast.LENGTH_SHORT).show();
            }
        });
    }

    private void downloadImage(final String uriString) {
        final File pictureStoragePath = getPictureStoragePath();

        pictureStoragePath.mkdirs();

        new Thread(new Runnable() {
            private URI uri;
            private InputStream pictureInputStream;
            private OutputStream pictureOutputStream;
            private MediaScannerConnection mediaScannerConnection;

            @Override
            public void run() {
                try {
                    uri = URI.create(uriString);
                    HttpClient httpClient = HttpClientFactory.create();
                    HttpGet httpGet = new HttpGet(uri);

                    HttpResponse httpResponse = httpClient.execute(httpGet);
                    pictureInputStream = httpResponse.getEntity().getContent();

                    String redirectLocation = HttpResponses.extractHeader(httpResponse, LOCATION);
                    if (redirectLocation != null) {
                        uri = URI.create(redirectLocation);
                    }

                    final String pictureFileName = getFileNameForUriAndHttpResponse(uri, httpResponse);
                    File pictureFile = new File(pictureStoragePath, pictureFileName);
                    final String pictureFileFullPath = pictureFile.toString();
                    pictureOutputStream = new FileOutputStream(pictureFile);

                    Streams.copyContent(pictureInputStream, pictureOutputStream);

                    loadPictureIntoGalleryApp(pictureFileFullPath);
                } catch (Exception exception) {
                    mHandler.post(new Runnable() {
                        @Override
                        public void run() {
                            showUserToast("Image failed to download.");
                            getMraidView().fireErrorEvent(STORE_PICTURE, "Error downloading and saving image file.");
                            Log.d("Adcash", "Error downloading and saving image file.");
                        }
                    });
                } finally {
                    Streams.closeStream(pictureInputStream);
                    Streams.closeStream(pictureOutputStream);
                }
            }

            private void loadPictureIntoGalleryApp(final String filename) {
                AdcashMediaScannerConnectionClient mediaScannerConnectionClient = new AdcashMediaScannerConnectionClient(filename, null);
                mediaScannerConnection = new MediaScannerConnection(getContext().getApplicationContext(), mediaScannerConnectionClient);
                mediaScannerConnectionClient.setMediaScannerConnection(mediaScannerConnection);
                mediaScannerConnection.connect();
            }
        }).start();
    }

    private void showUserDialog(final String imageUrl) {
        AlertDialog.Builder alertDialogDownloadImage = new AlertDialog.Builder(getContext());
        alertDialogDownloadImage
                .setTitle("Save Image")
                .setMessage("Download image to Picture gallery?")
                .setNegativeButton("Cancel", null)
                .setPositiveButton("Okay", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        downloadImage(imageUrl);
                    }
                })
                .setCancelable(true)
                .show();
    }

    protected void showVideo(String videoUrl) {
        MraidVideoPlayerActivity.startMraid(getContext(), videoUrl);
    }

    protected void getCurrentPosition(){
        getMraidView().fireErrorEvent(GET_CURRENT_POSITION, "Unsupported action getCurrentPosition");
    }

    protected void getDefaultPosition(){
        getMraidView().fireErrorEvent(GET_DEFAULT_POSITION, "Unsupported action getDefaultPosition");
    }

    protected void getMaxSize(){
        getMraidView().fireErrorEvent(GET_MAX_SIZE, "Unsupported action getMaxSize");
    }

    protected void getScreenSize(){
        getMraidView().fireErrorEvent(GET_SCREEN_SIZE, "Unsupported action getScreenSize");
    }

    protected void createCalendarEvent(Map<String, String> params) {
        Context context = getMraidView().getContext();
        if (Mraids.isCalendarAvailable(context)) {
            try {
                Map<String, Object> calendarParams = translateJSParamsToAndroidCalendarEventMapping(params);
                Intent intent = new Intent(Intent.ACTION_INSERT).setType(ANDROID_CALENDAR_CONTENT_TYPE);
                for (String key : calendarParams.keySet()) {
                    Object value = calendarParams.get(key);
                    if (value instanceof Long) {
                        intent.putExtra(key, ((Long) value).longValue());
                    } else if (value instanceof Integer) {
                        intent.putExtra(key, ((Integer) value).intValue());
                    } else {
                        intent.putExtra(key, (String) value);
                    }
                }
                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                context.startActivity(intent);
            } catch (ActivityNotFoundException anfe) {
                Log.d(LOGTAG, "no calendar app installed");
                getMraidView().fireErrorEvent(CREATE_CALENDAR_EVENT, "Action is unsupported on this device - no calendar app installed");
            } catch (IllegalArgumentException iae) {
                Log.d(LOGTAG, "create calendar: invalid parameters " + iae.getMessage());
                getMraidView().fireErrorEvent(CREATE_CALENDAR_EVENT, iae.getMessage());
            } catch (Exception exception){
                Log.d(LOGTAG, "could not create calendar event");
                getMraidView().fireErrorEvent(CREATE_CALENDAR_EVENT, "could not create calendar event");
            }
        } else {
            Log.d(LOGTAG, "unsupported action createCalendarEvent for devices pre-ICS");
            getMraidView().fireErrorEvent(CREATE_CALENDAR_EVENT, "Action is unsupported on this device (need Android version Ice Cream Sandwich or above)");
        }
    }

    private Map<String, Object> translateJSParamsToAndroidCalendarEventMapping(Map<String, String> params) throws Exception {
        Map<String, Object> validatedParamsMapping = new HashMap<String, Object>();
        if (!params.containsKey("description") || !params.containsKey("start")) {
            throw new IllegalArgumentException("Missing start and description fields");
        }

        validatedParamsMapping.put(CalendarContract.Events.TITLE, params.get("description"));

        if (params.containsKey("start") && params.get("start") != null) {
            Date startDateTime = parseDate(params.get("start"));
            if (startDateTime != null) {
                validatedParamsMapping.put(CalendarContract.EXTRA_EVENT_BEGIN_TIME, startDateTime.getTime());
            } else {
                throw new IllegalArgumentException("Invalid calendar event: start time is malformed. Date format expecting (yyyy-MM-DDTHH:MM:SS-xx:xx) or (yyyy-MM-DDTHH:MM-xx:xx) i.e. 2013-08-14T09:00:01-08:00");
            }
        } else {
            throw new IllegalArgumentException("Invalid calendar event: start is null.");
        }

        if (params.containsKey("end") && params.get("end") != null) {
            Date endDateTime = parseDate(params.get("end"));
            if (endDateTime != null) {
                validatedParamsMapping.put(CalendarContract.EXTRA_EVENT_END_TIME, endDateTime.getTime());
            } else {
                throw new IllegalArgumentException("Invalid calendar event: end time is malformed. Date format expecting (yyyy-MM-DDTHH:MM:SS-xx:xx) or (yyyy-MM-DDTHH:MM-xx:xx) i.e. 2013-08-14T09:00:01-08:00");
            }
        }

        if (params.containsKey("location")) {
            validatedParamsMapping.put(CalendarContract.Events.EVENT_LOCATION, params.get("location"));
        }

        if (params.containsKey("summary")) {
            validatedParamsMapping.put(CalendarContract.Events.DESCRIPTION, params.get("summary"));
        }

        if (params.containsKey("transparency")) {
            validatedParamsMapping.put(
                    CalendarContract.Events.AVAILABILITY,
                    params.get("transparency").equals("transparent") ?
                            CalendarContract.Events.AVAILABILITY_FREE :
                            CalendarContract.Events.AVAILABILITY_BUSY
            );
        }

        validatedParamsMapping.put(CalendarContract.Events.RRULE, parseRecurrenceRule(params));

        return validatedParamsMapping;
    }

    private Date parseDate(String dateTime) {
        Date result = null;
        for (int i=0; i<DATE_FORMATS.length; i++) {
            try {
                result = new SimpleDateFormat(DATE_FORMATS[i]).parse(dateTime);
                if (result != null) {
                    break;
                }
            } catch (ParseException e) {
                // an exception is okay, just try the next format and find the first one that works
            }
        }
        return result;
    }

    private String parseRecurrenceRule(Map<String, String> params) throws IllegalArgumentException {
        StringBuilder rule = new StringBuilder();
        if (params.containsKey("frequency")) {
            String frequency = params.get("frequency");
            int interval = -1;
            if (params.containsKey("interval")) {
                interval = Integer.parseInt(params.get("interval"));
            }
            if ("daily".equals(frequency)) {
                rule.append("FREQ=DAILY;");
                if (interval != -1) {
                    rule.append("INTERVAL=" + interval + ";");
                }
            } else if("weekly".equals(frequency)) {
                rule.append("FREQ=WEEKLY;");
                if (interval != -1) {
                    rule.append("INTERVAL=" + interval + ";");
                }
                if (params.containsKey("daysInWeek")) {
                    String weekdays = translateWeekIntegersToDays(params.get("daysInWeek"));
                    if (weekdays == null) {
                       throw new IllegalArgumentException("invalid ");
                    }
                    rule.append("BYDAY=" + weekdays + ";");
                }
            } else if("monthly".equals(frequency)) {
                rule.append("FREQ=MONTHLY;");
                if (interval != -1) {
                    rule.append("INTERVAL=" + interval + ";");
                }
                if (params.containsKey("daysInMonth")) {
                    String monthDays = translateMonthIntegersToDays(params.get("daysInMonth"));
                    if (monthDays == null) {
                        throw new IllegalArgumentException();
                    }
                    rule.append("BYMONTHDAY=" + monthDays + ";");
                }
            } else {
                throw new IllegalArgumentException("frequency is only supported for daily, weekly, and monthly.");
            }
        }
        return rule.toString();
    }

    private String translateWeekIntegersToDays(String expression) throws IllegalArgumentException{
        StringBuilder daysResult = new StringBuilder();
        boolean[] daysAlreadyCounted = new boolean[7];
        String[] days = expression.split(",");
        int dayNumber;
        for (int i=0; i<days.length; i++) {
            dayNumber = Integer.parseInt(days[i]);
            dayNumber = dayNumber == 7 ? 0 : dayNumber;
            if (!daysAlreadyCounted[dayNumber]) {
                daysResult.append(dayNumberToDayOfWeekString(dayNumber) + ",");
                daysAlreadyCounted[dayNumber] = true;
            }
        }
        if (days.length == 0) {
            throw new IllegalArgumentException("must have at least 1 day of the week if specifying repeating weekly");
        }
        daysResult.deleteCharAt(daysResult.length()-1);
        return daysResult.toString();
    }

    private String translateMonthIntegersToDays(String expression) throws IllegalArgumentException {
        StringBuilder daysResult = new StringBuilder();
        boolean[] daysAlreadyCounted = new boolean[2*MAX_NUMBER_DAYS_IN_MONTH +1]; //for -31 to 31
        String[] days = expression.split(",");
        int dayNumber;
        for (int i=0; i<days.length; i++) {
            dayNumber = Integer.parseInt(days[i]);
            if (!daysAlreadyCounted[dayNumber+MAX_NUMBER_DAYS_IN_MONTH]) {
                daysResult.append(dayNumberToDayOfMonthString(dayNumber) + ",");
                daysAlreadyCounted[dayNumber+MAX_NUMBER_DAYS_IN_MONTH] = true;
            }
        }
        if (days.length == 0) {
            throw new IllegalArgumentException("must have at least 1 day of the month if specifying repeating weekly");
        }
        daysResult.deleteCharAt(daysResult.length() - 1);
        return daysResult.toString();
    }

    private String dayNumberToDayOfWeekString(int number) throws IllegalArgumentException {
        String dayOfWeek;
        switch(number) {
            case 0: dayOfWeek="SU"; break;
            case 1: dayOfWeek="MO"; break;
            case 2: dayOfWeek="TU"; break;
            case 3: dayOfWeek="WE"; break;
            case 4: dayOfWeek="TH"; break;
            case 5: dayOfWeek="FR"; break;
            case 6: dayOfWeek="SA"; break;
            default: throw new IllegalArgumentException("invalid day of week " + number);
        }
        return dayOfWeek;
    }

    private String dayNumberToDayOfMonthString(int number) throws IllegalArgumentException {
        String dayOfMonth;
        // https://android.googlesource.com/platform/frameworks/opt/calendar/+/504844526f1b7afec048c6d2976ffb332670d5ba/src/com/android/calendarcommon2/EventRecurrence.java
        if (number != 0 && number >= -MAX_NUMBER_DAYS_IN_MONTH && number <= MAX_NUMBER_DAYS_IN_MONTH) {
            dayOfMonth = "" + number;
        } else {
            throw new IllegalArgumentException("invalid day of month " + number);
        }
        return dayOfMonth;
    }

    private void swapViewWithPlaceholderView() {
        ViewGroup parent = (ViewGroup) getMraidView().getParent();
        if (parent == null) return;

        int index;
        int count = parent.getChildCount();
        for (index = 0; index < count; index++) {
            if (parent.getChildAt(index) == getMraidView()) break;
        }

        mViewIndexInParent = index;
        parent.addView(mPlaceholderView, index,
                new ViewGroup.LayoutParams(getMraidView().getWidth(), getMraidView().getHeight()));
        parent.removeView(getMraidView());
    }

    private void expandLayouts(View expansionContentView, int expandWidth, int expandHeight) {
        int closeButtonSize = (int) (CLOSE_BUTTON_SIZE_DP * mDensity + 0.5f);
        if (expandWidth < closeButtonSize) expandWidth = closeButtonSize;
        if (expandHeight < closeButtonSize) expandHeight = closeButtonSize;

        View dimmingView = new View(getContext());
        dimmingView.setBackgroundColor(Color.TRANSPARENT);
        dimmingView.setOnTouchListener(new OnTouchListener() {
            public boolean onTouch(View v, MotionEvent event) {
                return true;
            }
        });

        mExpansionLayout.addView(dimmingView, new RelativeLayout.LayoutParams(
                RelativeLayout.LayoutParams.FILL_PARENT, RelativeLayout.LayoutParams.FILL_PARENT));

        mAdContainerLayout.addView(expansionContentView, new RelativeLayout.LayoutParams(
                RelativeLayout.LayoutParams.FILL_PARENT, RelativeLayout.LayoutParams.FILL_PARENT));

        RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(expandWidth, expandHeight);
        lp.addRule(RelativeLayout.CENTER_IN_PARENT);
        mExpansionLayout.addView(mAdContainerLayout, lp);
    }

    private void setOrientationLockEnabled(boolean enabled) {
        Context context = getContext();
        Activity activity = null;
        try {
            activity = (Activity) context;
            int requestedOrientation = enabled ?
                    activity.getResources().getConfiguration().orientation :
                    mOriginalRequestedOrientation;
            activity.setRequestedOrientation(requestedOrientation);
        } catch (ClassCastException e) {
            Log.d(LOGTAG, "Unable to modify device orientation.");
        }
    }

    protected void setNativeCloseButtonEnabled(boolean enabled) {
        if (mRootView == null) return;

        if (enabled) {
            if (mCloseButton == null) {
                StateListDrawable states = new StateListDrawable();
                states.addState(new int[] {-android.R.attr.state_pressed}, INTERSTITIAL_CLOSE_BUTTON_NORMAL.decodeImage(mRootView.getContext()));
                states.addState(new int[] {android.R.attr.state_pressed}, INTERSTITIAL_CLOSE_BUTTON_PRESSED.decodeImage(mRootView.getContext()));
                mCloseButton = new ImageButton(getContext());
                mCloseButton.setImageDrawable(states);
                mCloseButton.setBackgroundDrawable(null);
                mCloseButton.setOnClickListener(new OnClickListener() {
                    public void onClick(View v) {
                        MraidDisplayController.this.close();
                    }
                });
            }

            int buttonSize = (int) (CLOSE_BUTTON_SIZE_DP * mDensity + 0.5f);
            FrameLayout.LayoutParams buttonLayout = new FrameLayout.LayoutParams(
                    buttonSize, buttonSize, Gravity.RIGHT);
            mAdContainerLayout.addView(mCloseButton, buttonLayout);
        } else {
            mAdContainerLayout.removeView(mCloseButton);
        }

        MraidView view = getMraidView();
        if (view.getOnCloseButtonStateChangeListener() != null) {
            view.getOnCloseButtonStateChangeListener().onCloseButtonStateChange(view, enabled);
        }
    }

    protected void useCustomClose(boolean shouldUseCustomCloseButton) {
        mAdWantsCustomCloseButton = shouldUseCustomCloseButton;

        MraidView view = getMraidView();
        boolean enabled = !shouldUseCustomCloseButton;
        if (view.getOnCloseButtonStateChangeListener() != null) {
            view.getOnCloseButtonStateChangeListener().onCloseButtonStateChange(view, enabled);
        }
    }

    protected boolean checkViewable() {
        return true;
    }

    FrameLayout createAdContainerLayout() {
        return new FrameLayout(getContext());
    }

    RelativeLayout createExpansionLayout() {
        return new RelativeLayout(getContext());
    }

    FrameLayout createPlaceholderView() {
        return new FrameLayout(getContext());
    }

    private Context getContext() {
        return getMraidView().getContext();
    }

    protected void initializeSupportedFunctionsProperty() {
        Context context = getContext();
        getMraidView().fireChangeEventForProperty(
                new MraidSupportsProperty()
                        .withTel(isTelAvailable(context))
                        .withSms(isSmsAvailable(context))
                        .withCalendar(isCalendarAvailable(context))
                        .withInlineVideo(isInlineVideoAvailable(context))
                        .withStorePicture(isStorePictureSupported(context)));
    }

    private File getPictureStoragePath() {
        return new File(Environment.getExternalStorageDirectory(), "Pictures");
    }

    private String getFileNameForUriAndHttpResponse(final URI uri, final HttpResponse response) {
        final String path = uri.getPath();

        if (path == null) {
            return null;
        }

        String filename = new File(path).getName();

        Header header = response.getFirstHeader(MIME_TYPE_HEADER);
        if (header != null) {
            String[] fields = header.getValue().split(";");
            for (final String field : fields) {
                String extension;
                if (field.contains("image/")) {
                    extension = "." + field.split("/")[1];
                    if (!filename.endsWith(extension)) {
                        filename += extension;
                    }
                    break;
                }
            }
        }

        return filename;
    }

    private class AdcashMediaScannerConnectionClient implements MediaScannerConnection.MediaScannerConnectionClient {
        private final String mFilename;
        private final String mMimeType;
        private MediaScannerConnection mMediaScannerConnection;

        private AdcashMediaScannerConnectionClient(String filename, String mimeType) {
            mFilename = filename;
            mMimeType = mimeType;
        }

        private void setMediaScannerConnection(MediaScannerConnection connection) {
            mMediaScannerConnection = connection;
        }

        @Override
        public void onMediaScannerConnected() {
            if (mMediaScannerConnection != null) {
                mMediaScannerConnection.scanFile(mFilename, mMimeType);
            }
        }

        @Override
        public void onScanCompleted(String path, Uri uri) {
            if (mMediaScannerConnection != null) {
                mMediaScannerConnection.disconnect();
            }
        }
    }

    class OrientationBroadcastReceiver extends BroadcastReceiver {
        private int mLastRotation;
        private Context mContext;

        public void onReceive(Context context, Intent intent) {
            if(!isRegistered()) {
                return;
            }
            String action = intent.getAction();
            if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
                int orientation = MraidDisplayController.this.getDisplayRotation();
                if (orientation != mLastRotation) {
                    mLastRotation = orientation;
                    MraidDisplayController.this.onOrientationChanged(mLastRotation);
                }
            }
        }

        private boolean isRegistered() {
            return mContext != null;
        }

        public void register(Context context) {
            mContext = context;
            context.registerReceiver(this,
                    new IntentFilter(Intent.ACTION_CONFIGURATION_CHANGED));
        }

        public void unregister() {
            mContext.unregisterReceiver(this);
            mContext = null;
        }
    }
}




Java Source Code List

com.adcash.mobileads.AdAlertGestureListener.java
com.adcash.mobileads.AdAlertReporter.java
com.adcash.mobileads.AdConfiguration.java
com.adcash.mobileads.AdFetchTask.java
com.adcash.mobileads.AdFetcher.java
com.adcash.mobileads.AdLoadTask.java
com.adcash.mobileads.AdTypeTranslator.java
com.adcash.mobileads.AdUrlGenerator.java
com.adcash.mobileads.AdViewController.java
com.adcash.mobileads.AdcashActivity.java
com.adcash.mobileads.AdcashConversionTracker.java
com.adcash.mobileads.AdcashErrorCode.java
com.adcash.mobileads.AdcashInterstitial.java
com.adcash.mobileads.AdcashReferrerReceiver.java
com.adcash.mobileads.AdcashView.java
com.adcash.mobileads.Adcash.java
com.adcash.mobileads.BaseHtmlWebView.java
com.adcash.mobileads.BaseInterstitialActivity.java
com.adcash.mobileads.BaseUrlGenerator.java
com.adcash.mobileads.BaseVideoView.java
com.adcash.mobileads.BaseWebView.java
com.adcash.mobileads.CustomEventBannerAdapter.java
com.adcash.mobileads.CustomEventBanner.java
com.adcash.mobileads.CustomEventInterstitialAdapter.java
com.adcash.mobileads.CustomEventInterstitial.java
com.adcash.mobileads.DefaultBannerAdListener.java
com.adcash.mobileads.DefaultInterstitialAdListener.java
com.adcash.mobileads.DiskLruCache.java
com.adcash.mobileads.EventForwardingBroadcastReceiver.java
com.adcash.mobileads.FacebookKeywordProvider.java
com.adcash.mobileads.GpsHelper.java
com.adcash.mobileads.HtmlBannerWebView.java
com.adcash.mobileads.HtmlBanner.java
com.adcash.mobileads.HtmlInterstitialWebView.java
com.adcash.mobileads.HtmlInterstitial.java
com.adcash.mobileads.HtmlWebViewClient.java
com.adcash.mobileads.HtmlWebViewListener.java
com.adcash.mobileads.Log.java
com.adcash.mobileads.MraidAbstractController.java
com.adcash.mobileads.MraidActivity.java
com.adcash.mobileads.MraidBanner.java
com.adcash.mobileads.MraidBrowserController.java
com.adcash.mobileads.MraidBrowser.java
com.adcash.mobileads.MraidCommandFactory.java
com.adcash.mobileads.MraidCommandRegistry.java
com.adcash.mobileads.MraidCommand.java
com.adcash.mobileads.MraidDisplayController.java
com.adcash.mobileads.MraidInterstitial.java
com.adcash.mobileads.MraidProperty.java
com.adcash.mobileads.MraidVideoPlayerActivity.java
com.adcash.mobileads.MraidVideoView.java
com.adcash.mobileads.MraidView.java
com.adcash.mobileads.ResponseBodyInterstitial.java
com.adcash.mobileads.SharedPreferencesHelper.java
com.adcash.mobileads.TaskTracker.java
com.adcash.mobileads.Utils.java
com.adcash.mobileads.VastVideoDownloadTask.java
com.adcash.mobileads.VastVideoInterstitial.java
com.adcash.mobileads.VastVideoView.java
com.adcash.mobileads.ViewGestureDetector.java
com.adcash.mobileads.factories.AdFetchTaskFactory.java
com.adcash.mobileads.factories.AdFetcherFactory.java
com.adcash.mobileads.factories.AdViewControllerFactory.java
com.adcash.mobileads.factories.AdcashViewFactory.java
com.adcash.mobileads.factories.CustomEventBannerAdapterFactory.java
com.adcash.mobileads.factories.CustomEventBannerFactory.java
com.adcash.mobileads.factories.CustomEventInterstitialAdapterFactory.java
com.adcash.mobileads.factories.CustomEventInterstitialFactory.java
com.adcash.mobileads.factories.HtmlBannerWebViewFactory.java
com.adcash.mobileads.factories.HtmlInterstitialWebViewFactory.java
com.adcash.mobileads.factories.HttpClientFactory.java
com.adcash.mobileads.factories.MraidViewFactory.java
com.adcash.mobileads.factories.VastManagerFactory.java
com.adcash.mobileads.factories.VastVideoDownloadTaskFactory.java
com.adcash.mobileads.factories.ViewGestureDetectorFactory.java
com.adcash.mobileads.resource.Drawables.java
com.adcash.mobileads.resource.MraidJavascript.java
com.adcash.mobileads.util.AsyncTasks.java
com.adcash.mobileads.util.Base64.java
com.adcash.mobileads.util.DateAndTime.java
com.adcash.mobileads.util.Dips.java
com.adcash.mobileads.util.Files.java
com.adcash.mobileads.util.HttpClients.java
com.adcash.mobileads.util.HttpResponses.java
com.adcash.mobileads.util.HttpUtils.java
com.adcash.mobileads.util.Json.java
com.adcash.mobileads.util.Lists.java
com.adcash.mobileads.util.Mraids.java
com.adcash.mobileads.util.Reflection.java
com.adcash.mobileads.util.ResponseHeader.java
com.adcash.mobileads.util.Streams.java
com.adcash.mobileads.util.Strings.java
com.adcash.mobileads.util.VersionCode.java
com.adcash.mobileads.util.Views.java
com.adcash.mobileads.util.WebViews.java
com.adcash.mobileads.util.vast.VastManager.java
com.adcash.mobileads.util.vast.VastXmlManager.java