Update Material iOS to compile for visionOS

PiperOrigin-RevId: 641364760
diff --git a/components/AppBar/src/MDCAppBarNavigationController.m b/components/AppBar/src/MDCAppBarNavigationController.m
index 68e1d2f..eedf861 100644
--- a/components/AppBar/src/MDCAppBarNavigationController.m
+++ b/components/AppBar/src/MDCAppBarNavigationController.m
@@ -23,6 +23,13 @@
 
 #import <objc/runtime.h>
 
+#if defined(TARGET_OS_VISION) && TARGET_OS_VISION
+// For code review, use the review queue listed in go/material-visionos-review.
+#define IS_VISIONOS 1
+#else
+#define IS_VISIONOS 0
+#endif
+
 // Light-weight book-keeping associated with any pushed view controller.
 @interface MDCAppBarNavigationControllerInfo : NSObject
 
@@ -111,7 +118,9 @@
 
   [self injectAppBarIntoViewController:viewController];
 
+#if !IS_VISIONOS
   [self setNeedsStatusBarAppearanceUpdate];
+#endif
   [self setNeedsUpdateOfHomeIndicatorAutoHidden];
 }
 
@@ -122,7 +131,9 @@
     [self injectAppBarIntoViewController:viewController];
   }
 
+#if !IS_VISIONOS
   [self setNeedsStatusBarAppearanceUpdate];
+#endif
   [self setNeedsUpdateOfHomeIndicatorAutoHidden];
 }
 
diff --git a/components/Buttons/src/MDCButton.m b/components/Buttons/src/MDCButton.m
index 690a41f..b5c6004 100644
--- a/components/Buttons/src/MDCButton.m
+++ b/components/Buttons/src/MDCButton.m
@@ -35,6 +35,13 @@
 #import "UIFont+MaterialTypography.h"
 #import "MDCMath.h"
 
+#if defined(TARGET_OS_VISION) && TARGET_OS_VISION
+// For code review, use the review queue listed in go/material-visionos-review.
+#define IS_VISIONOS 1
+#else
+#define IS_VISIONOS 0
+#endif
+
 // TODO(ajsecord): Animate title color when animating between enabled/disabled states.
 // Non-trivial: http://corecocoa.wordpress.com/2011/10/04/animatable-text-color-of-uilabel/
 
@@ -373,7 +380,14 @@
     _inkView.frame = bounds;
     self.rippleView.frame = bounds;
   }
+
+#if IS_VISIONOS
+  UITraitCollection *current = [UITraitCollection currentTraitCollection];
+  self.titleLabel.frame =
+      MDCRectAlignToScale(self.titleLabel.frame, current ? [current displayScale] : 1.0);
+#else
   self.titleLabel.frame = MDCRectAlignToScale(self.titleLabel.frame, [UIScreen mainScreen].scale);
+#endif
 
   if ([self shouldInferMinimumAndMaximumSize]) {
     [self inferMinimumAndMaximumSize];
diff --git a/components/CollectionCells/src/MDCCollectionViewTextCell.m b/components/CollectionCells/src/MDCCollectionViewTextCell.m
index a26ceb1..7c1f32b 100644
--- a/components/CollectionCells/src/MDCCollectionViewTextCell.m
+++ b/components/CollectionCells/src/MDCCollectionViewTextCell.m
@@ -19,6 +19,13 @@
 
 #include <tgmath.h>
 
+#if defined(TARGET_OS_VISION) && TARGET_OS_VISION
+// For code review, use the review queue listed in go/material-visionos-review.
+#define IS_VISIONOS 1
+#else
+#define IS_VISIONOS 0
+#endif
+
 // Default cell heights.
 const CGFloat MDCCellDefaultOneLineHeight = 48;
 const CGFloat MDCCellDefaultOneLineWithAvatarHeight = 56;
@@ -61,14 +68,24 @@
 // Returns the closest pixel-aligned value higher than |value|, taking the scale factor into
 // account. At a scale of 1, equivalent to Ceil().
 static inline CGFloat AlignValueToUpperPixel(CGFloat value) {
+#if !IS_VISIONOS
   CGFloat scale = [[UIScreen mainScreen] scale];
+#else
+  UITraitCollection *current = [UITraitCollection currentTraitCollection];
+  CGFloat scale = current ? [current displayScale] : 1.0;
+#endif
   return (CGFloat)ceil(value * scale) / scale;
 }
 
 // Returns the closest pixel-aligned value lower than |value|, taking the scale factor into
 // account. At a scale of 1, equivalent to Floor().
 static inline CGFloat AlignValueToLowerPixel(CGFloat value) {
+#if !IS_VISIONOS
   CGFloat scale = [[UIScreen mainScreen] scale];
+#else
+  UITraitCollection *current = [UITraitCollection currentTraitCollection];
+  CGFloat scale = current ? [current displayScale] : 1.0;
+#endif
   return (CGFloat)floor(value * scale) / scale;
 }
 
diff --git a/components/Collections/src/private/MDCCollectionInfoBarView.m b/components/Collections/src/private/MDCCollectionInfoBarView.m
index 1b04dbb..cc23347 100644
--- a/components/Collections/src/private/MDCCollectionInfoBarView.m
+++ b/components/Collections/src/private/MDCCollectionInfoBarView.m
@@ -177,7 +177,14 @@
     if (!_backgroundBorderLayer) {
       _backgroundBorderLayer = [CALayer layer];
       _backgroundBorderLayer.borderColor = [UIColor colorWithWhite:0 alpha:(CGFloat)0.1].CGColor;
+#if defined(TARGET_OS_VISION) && TARGET_OS_VISION
+      // For code review, use the review queue listed in go/material-visionos-review.
+      UITraitCollection *current = [UITraitCollection currentTraitCollection];
+      CGFloat scale = current ? [current displayScale] : 1.0;
+      _backgroundBorderLayer.borderWidth = 1 / scale;
+#else
       _backgroundBorderLayer.borderWidth = 1 / [[UIScreen mainScreen] scale];
+#endif
       [self.backgroundView.layer addSublayer:_backgroundBorderLayer];
     }
   }
diff --git a/components/Collections/src/private/MDCCollectionViewEditor.m b/components/Collections/src/private/MDCCollectionViewEditor.m
index 6ecb510..0998550 100644
--- a/components/Collections/src/private/MDCCollectionViewEditor.m
+++ b/components/Collections/src/private/MDCCollectionViewEditor.m
@@ -298,7 +298,14 @@
 
   // Render snapshot.
   [_collectionView.layer renderInContext:cx];
+#if defined(TARGET_OS_VISION) && TARGET_OS_VISION
+  // For code review, use the review queue listed in go/material-visionos-review.
+  UITraitCollection *current = [UITraitCollection currentTraitCollection];
+  CGFloat scale = current ? [current displayScale] : 1.0;
+  _collectionView.layer.rasterizationScale = scale;
+#else
   _collectionView.layer.rasterizationScale = [UIScreen mainScreen].scale;
+#endif
   _collectionView.layer.shouldRasterize = YES;
   UIImage *screenshotImage = UIGraphicsGetImageFromCurrentImageContext();
 
diff --git a/components/Collections/src/private/MDCCollectionViewStyler.m b/components/Collections/src/private/MDCCollectionViewStyler.m
index 3c53181..23b2793 100644
--- a/components/Collections/src/private/MDCCollectionViewStyler.m
+++ b/components/Collections/src/private/MDCCollectionViewStyler.m
@@ -22,6 +22,13 @@
 
 #include <tgmath.h>
 
+#if defined(TARGET_OS_VISION) && TARGET_OS_VISION
+// For code review, use the review queue listed in go/material-visionos-review.
+#define IS_VISIONOS 1
+#else
+#define IS_VISIONOS 0
+#endif
+
 typedef NS_OPTIONS(NSUInteger, BackgroundCacheKey) {
   BackgroundCacheKeyFlat = 0,
   BackgroundCacheKeyTop = 1 << 0,
@@ -133,8 +140,16 @@
     // Cell separator defaults.
     _separatorColor = MDCPalette.greyPalette.tint300;
     _separatorInset = UIEdgeInsetsZero;
+
+#if IS_VISIONOS
+    UITraitCollection *current = [UITraitCollection currentTraitCollection];
+    CGFloat scale = current ? [current displayScale] : 1.0;
+    _separatorLineHeight = kCollectionViewCellSeparatorDefaultHeightInPixels / scale;
+#else
     _separatorLineHeight =
         kCollectionViewCellSeparatorDefaultHeightInPixels / [[UIScreen mainScreen] scale];
+#endif
+
     _shouldHideSeparators = NO;
 
     // Grid defaults.
@@ -301,7 +316,13 @@
   if ([self drawShadowForCellWithIsCardStye:isCardStyle
                                isGroupStyle:isGroupedStyle
                               isHighlighted:isHighlighted]) {
+#if IS_VISIONOS
+    UITraitCollection *current = [UITraitCollection currentTraitCollection];
+    CGFloat scale = current ? [current displayScale] : 1.0;
+    CGFloat mainScreenScale = scale;
+#else
     CGFloat mainScreenScale = [[UIScreen mainScreen] scale];
+#endif
     if (mainScreenScale > (CGFloat)2.1) {
       insets = kCollectionViewCellContentInsetsRetina3x;
     } else if (mainScreenScale > (CGFloat)1.1) {
@@ -680,7 +701,13 @@
 // We want to draw the borders and shadows on single retina-pixel boundaries if possible, but
 // we need to avoid doing this on non-retina devices because it'll look blurry.
 - (CGFloat)minPixelOffset {
+#if IS_VISIONOS
+  UITraitCollection *current = [UITraitCollection currentTraitCollection];
+  CGFloat scale = current ? [current displayScale] : 1.0;
+  return 1 / scale;
+#else
   return 1 / [[UIScreen mainScreen] scale];
+#endif
 }
 
 - (UIImage *)resizableImage:(UIImage *)image {
diff --git a/components/FlexibleHeader/src/MDCFlexibleHeaderView.m b/components/FlexibleHeader/src/MDCFlexibleHeaderView.m
index b645e9d..51f03e5 100644
--- a/components/FlexibleHeader/src/MDCFlexibleHeaderView.m
+++ b/components/FlexibleHeader/src/MDCFlexibleHeaderView.m
@@ -33,6 +33,13 @@
 #import "MDCMath.h"
 #import "MDCLayoutMetrics.h"
 
+#if defined(TARGET_OS_VISION) && TARGET_OS_VISION
+// For code review, use the review queue listed in go/material-visionos-review.
+#define IS_VISIONOS 1
+#else
+#define IS_VISIONOS 0
+#endif
+
 #if TARGET_IPHONE_SIMULATOR
 float UIAnimationDragCoefficient(void);  // Private API for simulator animation speed
 #endif
@@ -611,10 +618,12 @@
   info.hasInjectedTopContentInset = NO;
   scrollView.contentInset = insets;
 
+#if !IS_VISIONOS
   UIEdgeInsets scrollIndicatorInsets = scrollView.scrollIndicatorInsets;
   scrollIndicatorInsets.top -= info.injectedTopScrollIndicatorInset;
-  info.injectedTopScrollIndicatorInset = 0;
   scrollView.scrollIndicatorInsets = scrollIndicatorInsets;
+#endif
+  info.injectedTopScrollIndicatorInset = 0;
 }
 
 - (CGFloat)fhv_existingContentInsetAdjustmentForScrollView:(UIScrollView *)scrollView {
@@ -680,7 +689,11 @@
     scrollView.contentInset = insets;
   }
 
+#if IS_VISIONOS
+  BOOL statusBarIsHidden = YES;
+#else
   BOOL statusBarIsHidden = [UIApplication mdc_safeSharedApplication].statusBarHidden ? YES : NO;
+#endif
   if (_wasStatusBarHiddenIsValid && _wasStatusBarHidden != statusBarIsHidden &&
       !_isChangingStatusBarVisibility && !self.inferTopSafeAreaInsetFromViewController) {
     // Our status bar state has changed without our knowledge. UIKit will have already adjusted our
@@ -753,7 +766,11 @@
 
 - (CGFloat)fhv_accumulatorMax {
   BOOL shouldCollapseToStatusBar = [self fhv_shouldCollapseToStatusBar];
+#if IS_VISIONOS
+  CGFloat statusBarHeight = 0.0;
+#else
   CGFloat statusBarHeight = [UIApplication mdc_safeSharedApplication].statusBarFrame.size.height;
+#endif
   return (shouldCollapseToStatusBar
               ? MAX(0, self.minMaxHeight.minimumHeightWithTopSafeArea - statusBarHeight)
               : self.minMaxHeight.minimumHeightWithTopSafeArea) -
@@ -822,8 +839,12 @@
     _scrollPhaseValue = topEdge + self.minMaxHeight.minimumHeightWithTopSafeArea;
     CGFloat adjustedHeight = self.minMaxHeight.minimumHeightWithTopSafeArea;
     if ([self fhv_shouldCollapseToStatusBar]) {
+#if IS_VISIONOS
+      CGFloat statusBarHeight = 0.0;
+#else
       CGFloat statusBarHeight =
           [UIApplication mdc_safeSharedApplication].statusBarFrame.size.height;
+#endif
       adjustedHeight -= statusBarHeight;
     }
     if (adjustedHeight > 0) {
@@ -988,7 +1009,11 @@
     self.hidden = isHidden;
   }
 
+#if IS_VISIONOS
+  UIEdgeInsets scrollIndicatorInsets = _trackingScrollView.horizontalScrollIndicatorInsets;
+#else
   UIEdgeInsets scrollIndicatorInsets = _trackingScrollView.scrollIndicatorInsets;
+#endif
   scrollIndicatorInsets.top -= _trackingInfo.injectedTopScrollIndicatorInset;
 
   CGFloat existingContentInsetAdjustment =
diff --git a/components/FlexibleHeader/src/MDCFlexibleHeaderViewController.m b/components/FlexibleHeader/src/MDCFlexibleHeaderViewController.m
index 7f7459b..d790f37 100644
--- a/components/FlexibleHeader/src/MDCFlexibleHeaderViewController.m
+++ b/components/FlexibleHeader/src/MDCFlexibleHeaderViewController.m
@@ -28,6 +28,13 @@
 #import "MDCLayoutMetrics.h"
 #import <MDFTextAccessibility/MDFTextAccessibility.h>
 
+#if defined(TARGET_OS_VISION) && TARGET_OS_VISION
+// For code review, use the review queue listed in go/material-visionos-review.
+#define IS_VISIONOS 1
+#else
+#define IS_VISIONOS 0
+#endif
+
 @interface UIView ()
 - (UIEdgeInsets)safeAreaInsets;  // For pre-iOS 11 SDK targets.
 @end
@@ -136,8 +143,21 @@
 - (void)commonMDCFlexibleHeaderViewControllerInit {
   _inferPreferredStatusBarStyle = YES;
 
+#if IS_VISIONOS
+  UIWindow *keyWindow = nil;
+  for (UIScene *scene in UIApplication.sharedApplication.connectedScenes) {
+    if ([scene isKindOfClass:[UIWindowScene class]]) {
+      UIWindowScene *windowScene = (UIWindowScene *)scene;
+      keyWindow = windowScene.keyWindow;
+      break;
+    }
+  }
+  MDCFlexibleHeaderView *headerView =
+      [[MDCFlexibleHeaderView alloc] initWithFrame:keyWindow.bounds];
+#else
   MDCFlexibleHeaderView *headerView =
       [[MDCFlexibleHeaderView alloc] initWithFrame:[UIScreen mainScreen].bounds];
+#endif
   headerView.autoresizingMask = UIViewAutoresizingFlexibleWidth;
   headerView.delegate = self;
   _headerView = headerView;
@@ -152,6 +172,7 @@
 - (void)willMoveToParentViewController:(UIViewController *)parent {
   [super willMoveToParentViewController:parent];
 
+#if !IS_VISIONOS
   BOOL shouldDisableAutomaticInsetting = YES;
   // Prior to iOS 11 there was no way to know whether UIKit had injected insets into our
   // UIScrollView, so we disable automatic insetting on these devices. iOS 11 provides
@@ -161,6 +182,7 @@
   if (shouldDisableAutomaticInsetting) {
     parent.automaticallyAdjustsScrollViewInsets = NO;
   }
+#endif
 }
 
 - (void)didMoveToParentViewController:(UIViewController *)parent {
@@ -199,13 +221,18 @@
     // Querying the top layout guide ensures that the flexible header receives layout event when
     // the status bar visibility changes. This allows the flexible header to animate alongside any
     // status bar visibility changes.
+#if !IS_VISIONOS
     [self.parentViewController topLayoutGuide];
+#else
+    [self.parentViewController.view safeAreaLayoutGuide];
+#endif
   }
 
   if (self.topLayoutGuideAdjustmentEnabled) {
     [self updateTopLayoutGuide];
 
   } else {
+#if !IS_VISIONOS
     // Legacy behavior.
     for (NSLayoutConstraint *constraint in self.parentViewController.view.constraints) {
       // Because topLayoutGuide is a readonly property on a viewController we must manipulate
@@ -215,6 +242,7 @@
         self.topLayoutGuideConstraint = constraint;
       }
     }
+#endif
 
     // On moving to parentViewController, we calculate the height
     self.flexibleHeaderViewControllerHeightOffset = [self headerViewControllerHeight];
@@ -372,6 +400,10 @@
 
 - (NSLayoutConstraint *)fhv_topLayoutGuideConstraintForViewController:
     (UIViewController *)viewController {
+#if IS_VISIONOS
+  // We could look at the view's safe area anchors if this is incorrect.
+  return nil;
+#else
   // Note: accessing topLayoutGuide has the side effect of setting up all of the view controller
   // constraints. We need to access this property before we enter the for loop, otherwise
   // view.constraints will be empty.
@@ -383,6 +415,7 @@
     }
   }
   return foundConstraint;
+#endif
 }
 
 - (void)setTopLayoutGuideConstraint:(NSLayoutConstraint *)topLayoutGuideConstraint {
@@ -537,7 +570,11 @@
 - (CGFloat)headerViewControllerHeight {
   BOOL shiftEnabledForStatusBar =
       _headerView.shiftBehavior == MDCFlexibleHeaderShiftBehaviorEnabledWithStatusBar;
+#if IS_VISIONOS
+  CGFloat statusBarHeight = 0.0;
+#else
   CGFloat statusBarHeight = [UIApplication mdc_safeSharedApplication].statusBarFrame.size.height;
+#endif
   CGFloat height = MAX(_headerView.frame.origin.y + _headerView.frame.size.height,
                        shiftEnabledForStatusBar ? 0 : statusBarHeight);
   return height;
@@ -676,7 +713,9 @@
 
 - (void)flexibleHeaderViewNeedsStatusBarAppearanceUpdate:
     (__unused MDCFlexibleHeaderView *)headerView {
+#if !IS_VISIONOS
   [self setNeedsStatusBarAppearanceUpdate];
+#endif
 }
 
 - (void)flexibleHeaderViewFrameDidChange:(MDCFlexibleHeaderView *)headerView {
diff --git a/components/FlexibleHeader/src/private/MDCFlexibleHeaderHairline.m b/components/FlexibleHeader/src/private/MDCFlexibleHeaderHairline.m
index ba0138b..2694cfc 100644
--- a/components/FlexibleHeader/src/private/MDCFlexibleHeaderHairline.m
+++ b/components/FlexibleHeader/src/private/MDCFlexibleHeaderHairline.m
@@ -91,7 +91,13 @@
 
 - (CGRect)frame {
   CGRect bounds = self.containerView.bounds;
+#if defined(TARGET_OS_VISION) && TARGET_OS_VISION
+  // For code review, use the review queue listed in go/material-visionos-review.
+  UITraitCollection *current = [UITraitCollection currentTraitCollection];
+  CGFloat containerScreenScale = current ? [current displayScale] : 1.0;
+#else
   CGFloat containerScreenScale = self.containerView.window.screen.scale;
+#endif
   BOOL hasValidScreenScale = containerScreenScale > 0;
   CGFloat hairlineHeight = hasValidScreenScale ? ((CGFloat)1.0 / containerScreenScale) : 1;
   return CGRectMake(0, CGRectGetHeight(bounds) - hairlineHeight, CGRectGetWidth(bounds),
diff --git a/components/FlexibleHeader/src/private/MDCStatusBarShifter.m b/components/FlexibleHeader/src/private/MDCStatusBarShifter.m
index 3baa60c..fa05f3e 100644
--- a/components/FlexibleHeader/src/private/MDCStatusBarShifter.m
+++ b/components/FlexibleHeader/src/private/MDCStatusBarShifter.m
@@ -17,12 +17,21 @@
 #import "MDCStatusBarShifterDelegate.h"
 #import "MaterialApplication.h"
 
+#if defined(TARGET_OS_VISION) && TARGET_OS_VISION
+// For code review, use the review queue listed in go/material-visionos-review.
+#define IS_VISIONOS 1
+#else
+#define IS_VISIONOS 0
+#endif
+
 static NSTimeInterval kStatusBarBecomesInvalidAnimationDuration = 0.2;
 
+#if !IS_VISIONOS
 // If the time changes then we need to invalidate the status bar.
 // This value is the minimum amount of time we'll wait before invalidating the status bar even
 // after the time has changed in an effort to minimize flickering.
 static NSTimeInterval kMinimumNumberOfSecondsToWaitFor = 3;
+#endif
 
 // Simple state machine for the shifter:
 //          IsReal => IsSnapshot
@@ -71,12 +80,16 @@
     _enabled = YES;
     _snapshottingEnabled = YES;
 
+#if IS_VISIONOS
+    _originalStatusBarHeight = 0.0;
+#else
     _originalStatusBarHeight = [UIApplication mdc_safeSharedApplication].statusBarFrame.size.height;
     [[NSNotificationCenter defaultCenter]
         addObserver:self
            selector:@selector(statusBarDidChangeFrame)
                name:UIApplicationDidChangeStatusBarFrameNotification
              object:nil];
+#endif
   }
   return self;
 }
@@ -84,8 +97,10 @@
 #pragma mark - Notification
 
 - (void)statusBarDidChangeFrame {
+#if !IS_VISIONOS
   CGFloat statusBarHeight = [UIApplication mdc_safeSharedApplication].statusBarFrame.size.height;
   _originalStatusBarHeight = statusBarHeight == 0 ? _originalStatusBarHeight : statusBarHeight;
+#endif
 }
 
 #pragma mark - Private
@@ -179,6 +194,7 @@
       break;
     }
     case MDCStatusBarShifterStateIsSnapshot: {
+#if !IS_VISIONOS
       // Take a snapshot of the status bar.
       UIView *snapshotView = [[UIScreen mainScreen] snapshotViewAfterScreenUpdates:NO];
       UIView *clippingView = [[UIView alloc] init];
@@ -207,7 +223,7 @@
                                                        userInfo:nil
                                                         repeats:NO];
       [[NSRunLoop currentRunLoop] addTimer:_replicaInvalidatorTimer forMode:NSRunLoopCommonModes];
-
+#endif
       self.prefersStatusBarHidden = YES;
       break;
     }
@@ -268,10 +284,14 @@
 }
 
 - (BOOL)canUpdateStatusBarFrame {
+#if IS_VISIONOS
+  return NO;
+#else
   CGRect statusBarFrame = [[UIApplication mdc_safeSharedApplication] statusBarFrame];
   CGFloat statusBarHeight = MIN(statusBarFrame.size.width, statusBarFrame.size.height);
   return ((statusBarHeight == _originalStatusBarHeight) || _statusBarReplicaView ||
           _snapshotState == MDCStatusBarShifterStateInvalidSnapshot);
+#endif
 }
 
 - (BOOL)prefersStatusBarHidden {
@@ -289,7 +309,9 @@
 }
 
 - (void)didMoveToWindow {
+#if !IS_VISIONOS
   _originalStatusBarHeight = [UIApplication mdc_safeSharedApplication].statusBarFrame.size.height;
+#endif
 }
 
 @end
diff --git a/components/NavigationBar/src/MDCNavigationBar.m b/components/NavigationBar/src/MDCNavigationBar.m
index f6e9831..c617cbc 100644
--- a/components/NavigationBar/src/MDCNavigationBar.m
+++ b/components/NavigationBar/src/MDCNavigationBar.m
@@ -22,6 +22,13 @@
 #import "MaterialMath.h"
 #import "MaterialTypography.h"
 
+#if defined(TARGET_OS_VISION) && TARGET_OS_VISION
+// For code review, use the review queue listed in go/material-visionos-review.
+#define IS_VISIONOS 1
+#else
+#define IS_VISIONOS 0
+#endif
+
 static const NSUInteger kTitleFontSize = 20;
 static const CGFloat kNavigationBarDefaultHeight = 56;
 static const CGFloat kNavigationBarMinHeight = 24;
@@ -303,8 +310,12 @@
                                             withinBounds:textFrame
                                                alignment:titleVerticalAlignment];
   alignedFrame = [self mdc_frameAlignedHorizontally:alignedFrame alignment:self.titleAlignment];
+#if !IS_VISIONOS
   _titleLabel.frame = MDCRectAlignToScale(alignedFrame, self.window.screen.scale);
-
+#else
+  UITraitCollection *current = [UITraitCollection currentTraitCollection];
+  _titleLabel.frame = MDCRectAlignToScale(alignedFrame, current ? [current displayScale] : 1.0);
+#endif
   // Layout TitleView
   if (self.effectiveUserInterfaceLayoutDirection == UIUserInterfaceLayoutDirectionRightToLeft) {
     textFrame = MDFRectFlippedHorizontally(textFrame, CGRectGetWidth(self.bounds));
diff --git a/components/ProgressView/src/MDCProgressView.m b/components/ProgressView/src/MDCProgressView.m
index e411c65..e4b60d9 100644
--- a/components/ProgressView/src/MDCProgressView.m
+++ b/components/ProgressView/src/MDCProgressView.m
@@ -571,7 +571,16 @@
   CGRect progressFrame = self.bounds;
   if (_mode == MDCProgressViewModeDeterminate) {
     // Update progressView with the current progress value.
+#if defined(TARGET_OS_VISION) && TARGET_OS_VISION
+    // For code review, use the review queue listed in go/material-visionos-review.
+    UITraitCollection *current = [UITraitCollection currentTraitCollection];
+    CGFloat scale = current ? [current displayScale] : 1.0;
+    if (scale <= 0) {
+      scale = 1.0;
+    }
+#else
     CGFloat scale = self.window.screen.scale > 0 ? self.window.screen.scale : 1;
+#endif
     CGFloat pointWidth = self.progress * CGRectGetWidth(self.bounds);
     CGFloat pixelAlignedWidth = round(pointWidth * scale) / scale;
     progressFrame = CGRectMake(0, 0, pixelAlignedWidth, CGRectGetHeight(self.bounds));
diff --git a/components/Typography/src/UIFontDescriptor+MaterialTypography.m b/components/Typography/src/UIFontDescriptor+MaterialTypography.m
index 7c86c4b..38355ca 100644
--- a/components/Typography/src/UIFontDescriptor+MaterialTypography.m
+++ b/components/Typography/src/UIFontDescriptor+MaterialTypography.m
@@ -18,6 +18,13 @@
 
 #import "private/MDCFontTraits.h"
 
+#if defined(TARGET_OS_VISION) && TARGET_OS_VISION
+// For code review, use the review queue listed in go/material-visionos-review.
+#define IS_VISIONOS 1
+#else
+#define IS_VISIONOS 0
+#endif
+
 @implementation UIFontDescriptor (MaterialTypography)
 
 + (nonnull UIFontDescriptor *)mdc_fontDescriptorForMaterialTextStyle:(MDCFontTextStyle)style
@@ -65,7 +72,12 @@
   if ([UIApplication mdc_safeSharedApplication]) {
     sizeCategory = [UIApplication mdc_safeSharedApplication].preferredContentSizeCategory;
   } else {
+#if !IS_VISIONOS
     sizeCategory = UIScreen.mainScreen.traitCollection.preferredContentSizeCategory;
+#else
+    UITraitCollection *current = [UITraitCollection currentTraitCollection];
+    sizeCategory = current ? [current preferredContentSizeCategory] : UIContentSizeCategoryLarge;
+#endif
   }
 
   return [UIFontDescriptor mdc_fontDescriptorForMaterialTextStyle:style sizeCategory:sizeCategory];
diff --git a/components/Typography/src/private/MDCTypographyUtilities.m b/components/Typography/src/private/MDCTypographyUtilities.m
index 4210d67..dba3b09 100644
--- a/components/Typography/src/private/MDCTypographyUtilities.m
+++ b/components/Typography/src/private/MDCTypographyUtilities.m
@@ -13,6 +13,7 @@
 // limitations under the License.
 
 #import "MDCTypographyUtilities.h"
+#import <UIKit/UIKit.h>
 
 #import "MaterialApplication.h"
 
@@ -21,5 +22,10 @@
  if we are unable to query the device due to being in an extension.
  */
 UIContentSizeCategory GetCurrentSizeCategory(void) {
+#if defined(TARGET_OS_VISION) && TARGET_OS_VISION
+  // For code review, use the review queue listed in go/material-visionos-review.
+  return UITraitCollection.currentTraitCollection.preferredContentSizeCategory;
+#else
   return UIScreen.mainScreen.traitCollection.preferredContentSizeCategory;
+#endif
 }
diff --git a/components/private/KeyboardWatcher/src/MDCKeyboardWatcher.m b/components/private/KeyboardWatcher/src/MDCKeyboardWatcher.m
index 0507b86..497026d 100644
--- a/components/private/KeyboardWatcher/src/MDCKeyboardWatcher.m
+++ b/components/private/KeyboardWatcher/src/MDCKeyboardWatcher.m
@@ -94,6 +94,12 @@
     return;
   }
 
+#if defined(TARGET_OS_VISION) && TARGET_OS_VISION
+  // For code review, use the review queue listed in go/material-visionos-review.
+
+  // The keyboard on visionOS is undocked
+  self.keyboardFrame = CGRectZero;
+#else
   CGRect keyWindowBounds = [UIApplication mdc_safeSharedApplication].keyWindow.bounds;
   CGRect screenBounds = [[UIScreen mainScreen] bounds];
   CGRect intersection = CGRectIntersection(screenBounds, keyboardRect);
@@ -110,6 +116,7 @@
   } else {
     self.keyboardFrame = CGRectZero;
   }
+#endif
 }
 
 - (CGFloat)visibleKeyboardHeight {
diff --git a/components/private/UIMetrics/src/MDCLayoutMetrics.m b/components/private/UIMetrics/src/MDCLayoutMetrics.m
index 53d7ec5..f07dc73 100644
--- a/components/private/UIMetrics/src/MDCLayoutMetrics.m
+++ b/components/private/UIMetrics/src/MDCLayoutMetrics.m
@@ -16,8 +16,16 @@
 
 #import "UIApplication+MDCAppExtensions.h"
 
+#if defined(TARGET_OS_VISION) && TARGET_OS_VISION
+// For code review, use the review queue listed in go/material-visionos-review.
+#define IS_VISIONOS 1
+#else
+#define IS_VISIONOS 0
+#endif
+
 const CGFloat MDCFixedStatusBarHeightOnPreiPhoneXDevices = 20;
 
+#if !IS_VISIONOS
 static BOOL HasHardwareSafeAreas(void) {
   static BOOL hasHardwareSafeAreas = NO;
   static BOOL hasCheckedForHardwareSafeAreas = NO;
@@ -33,8 +41,12 @@
   }
   return hasHardwareSafeAreas;
 }
+#endif
 
 CGFloat MDCDeviceTopSafeAreaInset(void) {
+#if IS_VISIONOS
+  CGFloat topInset = 0.0;
+#else
   CGFloat topInset = MDCFixedStatusBarHeightOnPreiPhoneXDevices;
   // Devices with hardware safe area insets have fixed insets that depend on the device
   // orientation. On such devices, we aren't interested in the status bar's height because the
@@ -46,5 +58,6 @@
     UIEdgeInsets insets = [UIApplication mdc_safeSharedApplication].keyWindow.safeAreaInsets;
     topInset = insets.top;
   }
+#endif
   return topInset;
 }