@Override public void onScrollChanged(int deltaX, int deltaY) { // Reposition the header bar -- it's normally anchored to the top of the content, // but locks to the top of the screen on scroll int scrollY = mScrollView.getScrollY(); float newTop = Math.max(mPhotoHeightPixels, scrollY); mHeaderBox.setTranslationY(newTop); mAddScheduleButtonContainer.setTranslationY( newTop + mHeaderHeightPixels - mAddScheduleButtonContainerHeightPixels / 2); float gapFillProgress = 1; if (mPhotoHeightPixels != 0) { gapFillProgress = Math.min(Math.max(UIUtils.getProgress(scrollY, 0, mPhotoHeightPixels), 0), 1); } ViewCompat.setElevation(mHeaderBox, gapFillProgress * mMaxHeaderElevation); ViewCompat.setElevation( mAddScheduleButtonContainer, gapFillProgress * mMaxHeaderElevation + mFABElevation); ViewCompat.setElevation( mAddScheduleButton, gapFillProgress * mMaxHeaderElevation + mFABElevation); // Move background photo (parallax effect) mPhotoViewContainer.setTranslationY(scrollY * 0.5f); }
@Override protected void onResume() { super.onResume(); int actionBarSize = UIUtils.calculateActionBarSize(this); DrawShadowFrameLayout drawShadowFrameLayout = (DrawShadowFrameLayout) findViewById(R.id.main_content); if (drawShadowFrameLayout != null) { drawShadowFrameLayout.setShadowTopOffset(actionBarSize); } setContentTopClearance(actionBarSize); }
@Override public void onResume() { super.onResume(); // configure fragment's top clearance to take our overlaid controls (Action Bar // and spinner box) into account. int actionBarSize = UIUtils.calculateActionBarSize(getActivity()); DrawShadowFrameLayout drawShadowFrameLayout = (DrawShadowFrameLayout) getActivity().findViewById(R.id.main_content); if (drawShadowFrameLayout != null) { drawShadowFrameLayout.setShadowTopOffset(actionBarSize); } setContentTopClearance( actionBarSize + getResources().getDimensionPixelSize(R.dimen.explore_grid_padding)); }
private void processCommand(Context context, NotificationCommandModel command) { // Check format if (!"1.0.00".equals(command.format)) { LOGW(TAG, "GCM notification command has unrecognized format: " + command.format); return; } // Check app version if (!TextUtils.isEmpty(command.minVersion) || !TextUtils.isEmpty(command.maxVersion)) { LOGD(TAG, "Command has version range."); int minVersion = 0; int maxVersion = Integer.MAX_VALUE; try { if (!TextUtils.isEmpty(command.minVersion)) { minVersion = Integer.parseInt(command.minVersion); } if (!TextUtils.isEmpty(command.maxVersion)) { maxVersion = Integer.parseInt(command.maxVersion); } LOGD(TAG, "Version range: " + minVersion + " - " + maxVersion); PackageInfo pinfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0); LOGD(TAG, "My version code: " + pinfo.versionCode); if (pinfo.versionCode < minVersion) { LOGD( TAG, "Skipping command because our version is too old, " + pinfo.versionCode + " < " + minVersion); return; } if (pinfo.versionCode > maxVersion) { LOGD( TAG, "Skipping command because our version is too new, " + pinfo.versionCode + " > " + maxVersion); return; } } catch (NumberFormatException ex) { LOGE( TAG, "Version spec badly formatted: min=" + command.minVersion + ", max=" + command.maxVersion); return; } catch (Exception ex) { LOGE(TAG, "Unexpected problem doing version check.", ex); return; } } // Check if we are the right audience LOGD(TAG, "Checking audience: " + command.audience); if ("remote".equals(command.audience)) { if (PrefUtils.isAttendeeAtVenue(context)) { LOGD(TAG, "Ignoring notification because audience is remote and attendee is on-site"); return; } else { LOGD(TAG, "Relevant (attendee is remote)."); } } else if ("local".equals(command.audience)) { if (!PrefUtils.isAttendeeAtVenue(context)) { LOGD(TAG, "Ignoring notification because audience is on-site and attendee is remote."); return; } else { LOGD(TAG, "Relevant (attendee is local)."); } } else if ("all".equals(command.audience)) { LOGD(TAG, "Relevant (audience is 'all')."); } else { LOGE(TAG, "Invalid audience on GCM notification command: " + command.audience); return; } // Check if it expired Date expiry = command.expiry == null ? null : TimeUtils.parseTimestamp(command.expiry); if (expiry == null) { LOGW(TAG, "Failed to parse expiry field of GCM notification command: " + command.expiry); return; } else if (expiry.getTime() < UIUtils.getCurrentTime(context)) { LOGW(TAG, "Got expired GCM notification command. Expiry: " + expiry.toString()); return; } else { LOGD(TAG, "Message is still valid (expiry is in the future: " + expiry.toString() + ")"); } // decide the intent that will be fired when the user clicks the notification Intent intent; if (TextUtils.isEmpty(command.dialogText)) { // notification leads directly to the URL, no dialog if (TextUtils.isEmpty(command.url)) { intent = new Intent(context, MyScheduleActivity.class) .setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP); } else { intent = new Intent(Intent.ACTION_VIEW, Uri.parse(command.url)); } } else { // use a dialog intent = new Intent(context, MyScheduleActivity.class) .setFlags( Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); intent.putExtra( MyScheduleActivity.EXTRA_DIALOG_TITLE, command.dialogTitle == null ? "" : command.dialogTitle); intent.putExtra( MyScheduleActivity.EXTRA_DIALOG_MESSAGE, command.dialogText == null ? "" : command.dialogText); intent.putExtra( MyScheduleActivity.EXTRA_DIALOG_YES, command.dialogYes == null ? "OK" : command.dialogYes); intent.putExtra( MyScheduleActivity.EXTRA_DIALOG_NO, command.dialogNo == null ? "" : command.dialogNo); intent.putExtra(MyScheduleActivity.EXTRA_DIALOG_URL, command.url == null ? "" : command.url); } final String title = TextUtils.isEmpty(command.title) ? context.getString(R.string.app_name) : command.title; final String message = TextUtils.isEmpty(command.message) ? "" : command.message; // fire the notification ((NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE)) .notify( 0, new NotificationCompat.Builder(context) .setWhen(System.currentTimeMillis()) .setSmallIcon(R.drawable.ic_stat_notification) .setTicker(command.message) .setContentTitle(title) .setContentText(message) // .setColor(context.getResources().getColor(R.color.theme_primary)) // Note: setColor() is available in the support lib v21+. // We commented it out because we want the source to compile // against support lib v20. If you are using support lib // v21 or above on Android L, uncomment this line. .setContentIntent( PendingIntent.getActivity( context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT)) .setAutoCancel(true) .build()); }
private void displaySpeakersData(SessionDetailModel data) { final ViewGroup speakersGroup = (ViewGroup) getActivity().findViewById(R.id.session_speakers_block); // Remove all existing speakers (everything but first child, which is the header) for (int i = speakersGroup.getChildCount() - 1; i >= 1; i--) { speakersGroup.removeViewAt(i); } final LayoutInflater inflater = getActivity().getLayoutInflater(); boolean hasSpeakers = false; List<SessionDetailModel.Speaker> speakers = data.getSpeakers(); for (final SessionDetailModel.Speaker speaker : speakers) { String speakerHeader = speaker.getName(); if (!TextUtils.isEmpty(speaker.getCompany())) { speakerHeader += ", " + speaker.getCompany(); } final View speakerView = inflater.inflate(R.layout.speaker_detail, speakersGroup, false); final TextView speakerHeaderView = (TextView) speakerView.findViewById(R.id.speaker_header); final ImageView speakerImageView = (ImageView) speakerView.findViewById(R.id.speaker_image); final TextView speakerAbstractView = (TextView) speakerView.findViewById(R.id.speaker_abstract); final ImageView plusOneIcon = (ImageView) speakerView.findViewById(R.id.gplus_icon_box); final ImageView twitterIcon = (ImageView) speakerView.findViewById(R.id.twitter_icon_box); setUpSpeakerSocialIcon( speaker, twitterIcon, speaker.getTwitterUrl(), UIUtils.TWITTER_COMMON_NAME, UIUtils.TWITTER_PACKAGE_NAME); setUpSpeakerSocialIcon( speaker, plusOneIcon, speaker.getPlusoneUrl(), UIUtils.GOOGLE_PLUS_COMMON_NAME, UIUtils.GOOGLE_PLUS_PACKAGE_NAME); // A speaker may have both a Twitter and GPlus page, only a Twitter page or only a // GPlus page, or neither. By default, align the Twitter icon to the right and the GPlus // icon to its left. If only a single icon is displayed, align it to the right. determineSocialIconPlacement(plusOneIcon, twitterIcon); if (!TextUtils.isEmpty(speaker.getImageUrl()) && mSpeakersImageLoader != null) { mSpeakersImageLoader.loadImage(speaker.getImageUrl(), speakerImageView); } speakerHeaderView.setText(speakerHeader); speakerImageView.setContentDescription( getString(R.string.speaker_googleplus_profile, speakerHeader)); UIUtils.setTextMaybeHtml(speakerAbstractView, speaker.getAbstract()); if (!TextUtils.isEmpty(speaker.getUrl())) { speakerImageView.setEnabled(true); speakerImageView.setOnClickListener( new View.OnClickListener() { @Override public void onClick(View view) { Intent speakerProfileIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(speaker.getUrl())); speakerProfileIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET); UIUtils.preferPackageForIntent( getActivity(), speakerProfileIntent, UIUtils.GOOGLE_PLUS_PACKAGE_NAME); startActivity(speakerProfileIntent); } }); } else { speakerImageView.setEnabled(false); speakerImageView.setOnClickListener(null); } speakersGroup.addView(speakerView); hasSpeakers = true; } speakersGroup.setVisibility(hasSpeakers ? View.VISIBLE : View.GONE); updateEmptyView(data); }
private void displaySessionData(final SessionDetailModel data) { mTitle.setText(data.getSessionTitle()); mSubtitle.setText(data.getSessionSubtitle()); mPhotoViewContainer.setBackgroundColor( UIUtils.scaleSessionColorToDefaultBG(data.getSessionColor())); if (data.hasPhotoUrl()) { mHasPhoto = true; mNoPlaceholderImageLoader.loadImage( data.getPhotoUrl(), mPhotoView, new RequestListener<String, Bitmap>() { @Override public boolean onException( Exception e, String model, Target<Bitmap> target, boolean isFirstResource) { mHasPhoto = false; recomputePhotoAndScrollingMetrics(); return false; } @Override public boolean onResourceReady( Bitmap resource, String model, Target<Bitmap> target, boolean isFromMemoryCache, boolean isFirstResource) { // Trigger image transition recomputePhotoAndScrollingMetrics(); return false; } }); recomputePhotoAndScrollingMetrics(); } else { mHasPhoto = false; recomputePhotoAndScrollingMetrics(); } tryExecuteDeferredUiOperations(); // Handle Keynote as a special case, where the user cannot remove it // from the schedule (it is auto added to schedule on sync) mAddScheduleButton.setVisibility( (AccountUtils.hasActiveAccount(getContext()) && !data.isKeynote()) ? View.VISIBLE : View.INVISIBLE); displayTags(data); if (!data.isKeynote()) { showStarredDeferred(data.isInSchedule(), false); } if (!TextUtils.isEmpty(data.getSessionAbstract())) { UIUtils.setTextMaybeHtml(mAbstract, data.getSessionAbstract()); mAbstract.setVisibility(View.VISIBLE); } else { mAbstract.setVisibility(View.GONE); } // Build requirements section final View requirementsBlock = getActivity().findViewById(R.id.session_requirements_block); final String sessionRequirements = data.getRequirements(); if (!TextUtils.isEmpty(sessionRequirements)) { UIUtils.setTextMaybeHtml(mRequirements, sessionRequirements); requirementsBlock.setVisibility(View.VISIBLE); } else { requirementsBlock.setVisibility(View.GONE); } final ViewGroup relatedVideosBlock = (ViewGroup) getActivity().findViewById(R.id.related_videos_block); relatedVideosBlock.setVisibility(View.GONE); updateEmptyView(data); updateTimeBasedUi(data); if (data.getLiveStreamVideoWatched()) { mPhotoView.setColorFilter(getContext().getResources().getColor(R.color.video_scrim_watched)); mLiveStreamPlayIconAndText.setText(getString(R.string.session_replay)); } if (data.hasLiveStream()) { mLiveStreamPlayIconAndText.setOnClickListener( new View.OnClickListener() { @Override public void onClick(View v) { String videoId = YouTubeUtils.getVideoIdFromSessionData( data.getYouTubeUrl(), data.getLiveStreamId()); YouTubeUtils.showYouTubeVideo(videoId, getActivity()); } }); } fireAnalyticsScreenView(data.getSessionTitle()); mHandler.post( new Runnable() { @Override public void run() { onScrollChanged(0, 0); // trigger scroll handling mScrollViewChild.setVisibility(View.VISIBLE); // mAbstract.setTextIsSelectable(true); } }); mTimeHintUpdaterRunnable = new Runnable() { @Override public void run() { if (getActivity() == null) { // Do not post a delayed message if the activity is detached. return; } updateTimeBasedUi(data); mHandler.postDelayed( mTimeHintUpdaterRunnable, SessionDetailConstants.TIME_HINT_UPDATE_INTERVAL); } }; mHandler.postDelayed( mTimeHintUpdaterRunnable, SessionDetailConstants.TIME_HINT_UPDATE_INTERVAL); }