com.google.android.apps.santatracker.presentquest.ProfileActivity.java Source code

Java tutorial

Introduction

Here is the source code for com.google.android.apps.santatracker.presentquest.ProfileActivity.java

Source

/*
 * Copyright (C) 2016 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.google.android.apps.santatracker.presentquest;

import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.FragmentManager;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import com.google.android.apps.santatracker.presentquest.model.Avatars;
import com.google.android.apps.santatracker.presentquest.model.User;
import com.google.android.apps.santatracker.presentquest.model.Workshop;
import com.google.android.apps.santatracker.presentquest.ui.BounceInAnimator;
import com.google.android.apps.santatracker.presentquest.util.Config;
import com.google.android.apps.santatracker.presentquest.util.FuzzyLocationUtil;
import com.google.android.apps.santatracker.presentquest.util.PreferencesUtil;
import com.google.android.apps.santatracker.util.FontHelper;
import com.google.android.apps.santatracker.util.MeasurementManager;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.UiSettings;
import com.google.android.gms.maps.model.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.MapStyleOptions;
import com.google.android.gms.maps.model.MarkerOptions;
import com.google.firebase.analytics.FirebaseAnalytics;

import java.util.List;

public class ProfileActivity extends AppCompatActivity implements View.OnClickListener {

    private static final String TAG = "PQ(ProfileActivity)";

    private static final int MAX_WORKSHOPS = 3;
    private static final int RC_MOVE_WORKSHOP = 9001;

    public static final String EXTRA_LEVELED_UP = "extra_leveled_up";
    public static final String EXTRA_LAST_LOCATION = "extra_last_location";

    private ImageView mAvatarView;
    private TextView mLevelTextView;

    private Workshop[] mWorkshops = new Workshop[MAX_WORKSHOPS];
    private SupportMapFragment[] mMaps = new SupportMapFragment[MAX_WORKSHOPS];
    private WorkshopMapListener[] mListeners = new WorkshopMapListener[MAX_WORKSHOPS];

    private int mAvatarIndex;

    private User mUser;

    private PreferencesUtil mPrefs;

    private FirebaseAnalytics mAnalytics;

    private Config mConfig;

    private LatLng mLatLng;

    public static Intent getIntent(Context context, boolean leveledUp, LatLng location) {
        Intent intent = new Intent(context, ProfileActivity.class);
        intent.putExtra(EXTRA_LEVELED_UP, leveledUp);
        intent.putExtra(EXTRA_LAST_LOCATION, location);

        return intent;
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_profile);

        // [ANALYTICS]
        mAnalytics = FirebaseAnalytics.getInstance(this);
        MeasurementManager.recordScreenView(mAnalytics, getString(R.string.analytics_screen_pq_profile));

        // Config
        mConfig = new Config();

        // Get the current user
        mUser = User.get();

        // Preferences
        mPrefs = new PreferencesUtil(this);

        mAvatarView = (ImageView) findViewById(R.id.profile_user_image);
        mLevelTextView = (TextView) findViewById(R.id.text_current_level);

        // Make text santa-style
        FontHelper.makeLobster((TextView) findViewById(R.id.text_workshops), false);

        // Set up lock text
        ((TextView) findViewById(R.id.workshop_2_lock_text))
                .setText(getString(R.string.unlock_at_level, User.WORKSHOP_2_LEVEL));
        ((TextView) findViewById(R.id.workshop_3_lock_text))
                .setText(getString(R.string.unlock_at_level, User.WORKSHOP_3_LEVEL));

        // Get position passed in
        if (getIntent() != null && getIntent().getParcelableExtra(EXTRA_LAST_LOCATION) != null) {
            mLatLng = getIntent().getParcelableExtra(EXTRA_LAST_LOCATION);
        }

        // Click listeners
        mAvatarView.setOnClickListener(this);
        findViewById(R.id.button_edit_1).setOnClickListener(this);
        findViewById(R.id.button_edit_2).setOnClickListener(this);
        findViewById(R.id.button_edit_3).setOnClickListener(this);
        findViewById(R.id.arrow_left).setOnClickListener(this);
        findViewById(R.id.arrow_right).setOnClickListener(this);

        // Get map fragments
        FragmentManager fm = getSupportFragmentManager();
        mMaps[0] = (SupportMapFragment) fm.findFragmentById(R.id.map_workshop_1);
        mMaps[1] = (SupportMapFragment) fm.findFragmentById(R.id.map_workshop_2);
        mMaps[2] = (SupportMapFragment) fm.findFragmentById(R.id.map_workshop_3);

        // Load workshops
        loadWorkshops();

        // Load map fragments
        for (int i = 0; i < MAX_WORKSHOPS; i++) {
            mListeners[i] = new WorkshopMapListener(this, mWorkshops[i]);
            mMaps[i].getMapAsync(mListeners[i]);
        }

        setUserProgress();
    }

    @Override
    protected void onStart() {
        super.onStart();

        // Special animation for leveling up
        if (getIntent() != null && getIntent().getBooleanExtra(EXTRA_LEVELED_UP, false)) {
            bounceInAvatar();
        }
    }

    private void loadWorkshops() {
        // Get a list of all workshops in order of ascending ID (aka new to old).
        List<Workshop> all = Workshop.listAll(Workshop.class, "id ASC");
        for (int i = 0; i < MAX_WORKSHOPS; i++) {
            if (all.size() > i) {
                mWorkshops[i] = all.get(i);
            } else {
                mWorkshops[i] = null;
            }
        }
    }

    private void refreshWorkshops() {
        loadWorkshops();
        for (int i = 0; i < MAX_WORKSHOPS; i++) {
            mListeners[i].setWorkshop(mWorkshops[i]);
        }
    }

    private boolean isAnyWorkshopNearby() {
        for (Workshop workshop : mWorkshops) {
            if (workshop != null
                    && Distance.between(mLatLng, workshop.getLatLng()) < mConfig.REACHABLE_RADIUS_METERS) {
                return true;
            }
        }

        return false;
    }

    private void setUserProgress() {
        mAvatarIndex = mUser.getLevel() - 1;
        mLevelTextView.setText(String.valueOf(mUser.getLevel()));
        mAvatarView.setImageDrawable(ContextCompat.getDrawable(this, mUser.getAvatar()));

        // Can't edit workshop 1 location until you've at least collected a present
        setEditButtonVisible(findViewById(R.id.button_edit_1), mPrefs.getHasCollectedPresent());

        // Lock workshop 2
        boolean secondWorkshopUnlocked = mUser.getMaxPresentsCollected() >= 2;
        if (secondWorkshopUnlocked) {
            findViewById(R.id.workshop_2_scrim).setVisibility(View.GONE);
        } else {
            findViewById(R.id.workshop_2_scrim).setVisibility(View.VISIBLE);
        }
        setEditButtonVisible(findViewById(R.id.button_edit_2), secondWorkshopUnlocked);

        // Lock workshop 3
        boolean thirdWorkshopUnlocked = mUser.getMaxPresentsCollected() >= 3;
        if (thirdWorkshopUnlocked) {
            findViewById(R.id.workshop_3_scrim).setVisibility(View.GONE);
        } else {
            findViewById(R.id.workshop_3_scrim).setVisibility(View.GONE);
        }
        setEditButtonVisible(findViewById(R.id.button_edit_3), thirdWorkshopUnlocked);

        // Allow or deny workshop "magnet"-ing if we don't know the location or if the user
        // is already near a workshop
        if (mLatLng == null || isAnyWorkshopNearby()) {
            setEditButtonVisible(findViewById(R.id.button_edit_1), false);
            setEditButtonVisible(findViewById(R.id.button_edit_2), false);
            setEditButtonVisible(findViewById(R.id.button_edit_3), false);
        }
    }

    private void setEditButtonVisible(View button, boolean visible) {
        if (visible) {
            // Show the button at full strength
            button.setVisibility(View.VISIBLE);
            button.setAlpha(1.0f);
        } else if (isDebug()) {
            // When debugging never hide the buttons, just dim them
            button.setAlpha(0.5f);
        } else {
            // When not debugging, hide the button fully
            button.setVisibility(View.GONE);
        }
    }

    private void bounceInAvatar() {
        mAvatarView.postDelayed(new Runnable() {
            @Override
            public void run() {
                BounceInAnimator.animate(mAvatarView);
            }
        }, 750);
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == RC_MOVE_WORKSHOP) {
            if (resultCode == RESULT_OK) {
                Toast.makeText(this, getString(R.string.workshop_moved), Toast.LENGTH_SHORT).show();
                refreshWorkshops();

                // [ANALYTICS]
                MeasurementManager.recordWorkshopMoved(mAnalytics);
            } else {
                Toast.makeText(this, getString(R.string.move_canceled), Toast.LENGTH_SHORT).show();
            }
        }
    }

    public boolean needsNearbyWorkshop() {
        if (mLatLng != null && mUser.getBagFillPercentage() >= 100f) {
            // Check if any workshop is within a certain radius (default 1km)
            for (Workshop workshop : mWorkshops) {
                if (Distance.between(workshop.getLatLng(), mLatLng) < mConfig.NEARBY_WORKSHOP_RADIUS) {
                    return false;
                }
            }

            // No close workshops
            return true;
        }

        return false;
    }

    public void onMagnetWorkshopClick(Workshop workshop) {
        // Allow the user to move the workshop if they have not moved it today or if their bag
        // is full and they don't have any workshops within 1km
        if (workshop != null && !(workshop.isMovable() || needsNearbyWorkshop())) {
            Toast.makeText(this, getString(R.string.workshop_move_too_soon), Toast.LENGTH_SHORT).show();
            return;
        }

        // Move workshop to current location
        if (mLatLng != null) {
            // Create workshop if necessary
            if (workshop == null) {
                workshop = new Workshop();
            }

            // Update workshop
            LatLng fuzzyLocation = FuzzyLocationUtil.fuzz(mLatLng);
            workshop.setLatLng(fuzzyLocation);
            workshop.saveWithTimestamp();

            // [ANALYTICS]
            MeasurementManager.recordWorkshopMoved(mAnalytics);
        }

        // Refresh workshops
        refreshWorkshops();
    }

    public void onEditWorkshopClick(Workshop workshop) {
        if (workshop != null && !workshop.isMovable()) {
            Toast.makeText(this, getString(R.string.workshop_move_too_soon), Toast.LENGTH_SHORT).show();
        } else {
            // May need to create workshop first
            if (workshop == null) {
                workshop = new Workshop();
                workshop.setLatLng(Workshop.NULL_LATLNG);

                workshop.save();
            }

            Intent intent = new Intent(this, MapsActivity.class);
            intent.setAction(MapsActivity.ACTION_MOVE_WORKSHOP);
            intent.putExtra(MapsActivity.EXTRA_MOVE_WORKSHOP_ID, workshop.getId());

            startActivityForResult(intent, RC_MOVE_WORKSHOP);
        }
    }

    private void scrollAvatar(int delta) {
        mAvatarIndex = mAvatarIndex + delta;

        // Wrap around 0 --> last
        if (mAvatarIndex < 0) {
            mAvatarIndex = Avatars.NUM_AVATARS - 1;
        }

        // Wrap around last --> 0
        if (mAvatarIndex >= Avatars.NUM_AVATARS) {
            mAvatarIndex = 0;
        }

        // Set image
        int levelNumber = mAvatarIndex + 1;
        boolean locked = levelNumber > mUser.getLevel();
        if (locked) {
            mAvatarView.setImageResource(Avatars.AVATARS_LOCKED[mAvatarIndex]);
        } else {
            mAvatarView.setImageResource(Avatars.AVATARS_UNLOCKED[mAvatarIndex]);
        }

        // Set level text
        mLevelTextView.setText(String.valueOf(levelNumber));
    }

    @Override
    public void onClick(View v) {
        if (v.getId() == R.id.button_edit_1) {
            onMagnetWorkshopClick(mWorkshops[0]);
        }

        if (v.getId() == R.id.button_edit_2) {
            // Check if user has unlocked second workshop
            if (mUser.getMaxWorkshops() < 2) {
                return;
            }

            onMagnetWorkshopClick(mWorkshops[1]);
        }

        if (v.getId() == R.id.button_edit_3) {
            // Check if user has unlocked third workshop
            if (mUser.getMaxWorkshops() < 3) {
                return;
            }

            onMagnetWorkshopClick(mWorkshops[2]);
        }

        if (v.getId() == R.id.profile_user_image) {
            supportFinishAfterTransition();
        }

        if (v.getId() == R.id.arrow_left) {
            scrollAvatar(-1);
        }

        if (v.getId() == R.id.arrow_right) {
            scrollAvatar(1);
        }
    }

    private boolean isDebug() {
        return getPackageName().contains("debug");
    }

    private class WorkshopMapListener implements OnMapReadyCallback {

        Context context;
        Workshop workshop;

        GoogleMap googleMap;

        WorkshopMapListener(Context context, Workshop workshop) {
            this.context = context;
            this.workshop = workshop;
        }

        @Override
        public void onMapReady(GoogleMap googleMap) {
            this.googleMap = googleMap;

            // Santa Style
            googleMap.setMapStyle(MapStyleOptions.loadRawResourceStyle(context, R.raw.map_style));

            // Control map UI
            UiSettings settings = googleMap.getUiSettings();
            settings.setMapToolbarEnabled(false);
            settings.setMyLocationButtonEnabled(false);

            // Prevent Google Maps from launching
            googleMap.setOnMapClickListener(new GoogleMap.OnMapClickListener() {
                @Override
                public void onMapClick(LatLng latLng) {
                    // TODO: No-op
                }
            });

            // Show workshop
            setWorkshop(workshop);
        }

        public void setWorkshop(Workshop workshop) {
            this.workshop = workshop;

            if (workshop != null && googleMap != null) {
                LatLng workshopLatLng = workshop.getLatLng();

                googleMap.clear();
                googleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(workshopLatLng, 17f));
                googleMap.addMarker(new MarkerOptions()
                        .icon(BitmapDescriptorFactory.fromResource(R.drawable.workshop)).position(workshopLatLng));
            }
        }
    }
}